Exploring Subsetted or Grouped Data
Last week, we explored how your data was defined, how it was categorized, and how missing values were represented. Through this exercise, we were able to develop a good general overview of the observations, variables, and values in our datasets. Sometimes, however, we want to be able to zoom in to specific areas of our dataset and explore what is going on in that area. We also sometimes want to be able to zoom out - summarizing something across groups of observations in our data. As we prepare to visualize variation and co-variation in the dataset, let’s first go over how we can both zoom in and zoom out on our datasets.
Zooming in - Exploring Filtered Categorical Data
Filtering to a Category
Filtering is one way we can zoom in on our data - exploring only those observations that meet a particular criteria.
For instance, last week we learned above that one criteria for being designated as a Critical Access Hospital is that the hospital must have 25 or fewer inpatient beds. We may want to see how the values for BEDS change when we filter to (or zoom into) just those observations representing critical access hospitals. Below I will do this, select the BEDS variable, and call summary().
#df %>% filter(CATEGORICAL_VARIABLE == "VALUE") %>% select(NUMERIC_VARIABLE) %>% summary()
hospitals %>% filter(TYPE == "CRITICAL ACCESS") %>% select(BEDS) %>% summary()
BEDS
Min. : 3.0
1st Qu.: 22.0
Median : 25.0
Mean : 27.7
3rd Qu.: 25.0
Max. :286.0
NA's :42
We can see that there are some hospitals in the US that have been designated as critical access hospitals that have more than 25 beds. Since this does not align with the criteria for critical access hospitals that we discovered in our research, it is likely something that we will want to investigate further.
Filtering to Numeric Observations Above or Below a Threshold
We may also want to see which states have hospitals with more than 1500 beds. To do so, we would filter the data to those observations where BEDS is greater than 1500, and then we would check the distinct() STATES remaining in the data.
#df %>% filter(NUMBERIC_VARIABLE > VALUE) %>% distinct(CATEGORICAL_VARIABLE)
hospitals %>% filter(BEDS > 1500) %>% distinct(STATE)
From this exercise, we can see that only two states have hospitals with more than 1500 beds available.
Zooming out - aka grouping common values and summarizing
At times, we are seeking to get a broader picture of what’s going on in our dataset than provided - grouping observations that share a common value and then performing a calculation to summarize something within each of those groups. For instance, I may want to know the total number of hospital beds per state. To calculate this, I would need to group all of the hospital observations by state and then sum the total number of beds in each group.
In such cases, we can call group_by() to aggregate the observations with common variable values into groups. Then we will call summarize() to perform a calculation within each of those groups. summarize() takes a set of values and a calculation method and returns a single value. For instance, if we call summarize() with a numeric column in our dataset and “mean” as a calculation method, it will return the average of all the numeric values in that column. When called in conjunction with group_by(), it takes a set of values for each group and a calculation method and returns a single value for each group.
For the hospitals dataset, we will group the observations by STATE and then use summarize to calculate the sum of BEDS per state.
#df %>% group_by(CATEGORICAL_VARIABLE) %>% summarize(NEW_VARIABLE_NAME = sum(NUMBERIC_VARIABLE, na.rm = TRUE)) %>% ungroup()
hospitals %>% group_by(STATE) %>% summarize(state_beds = sum(BEDS, na.rm = TRUE)) %>% ungroup()
Notice that I close each of these calls with ungroup(). When we group_by() a variable, any subsequent function calls will continue to be performed on the grouped data, unless we ungroup() it. This can be important if we want to filter to specific values after we summarize() the data. Assuming that we don’t want to perform a filter operation within each group but on the entire new dataframe created after summarizing, we need to ungroup() the data before performing the filter() operation.
Note how we are choosing to ignore NA values above by calling na.rm = TRUE. When we do so, we need to keep in mind that we are not summarizing across all observations in the dataset, but only those for which there is a value listed in the variable we are operating on. Why might it be important to make communicate that we’ve made this move when we are presenting our data?
From this function, we see the number of beds across all hospitals per state. Depending on the question we are asking, this may or may not be relevant. For instance, if I’m wondering how much hospital infrastructure is available to support Covid-19 patients, one (of a number of factors) I need to consider before presenting this data is which types of hospitals are accepting Covid-19 patients. Are rehabilitation hospitals accepting patients? Psychiatric hospitals? Military hospitals? If they aren’t now, will they at some point? Further, some states are talking about cordoning off hotels for Covid-19 patients. How do we account for this change in the number of hospital beds (something definitely not represented in our data based on the way hospital has been defined). We need to do external research to answer these questions. Then we may wish to filter our data to relevant hospital types. For instance, at this moment, we may filter our data to only include beds at General Acute Care Hospitals. We also know that some hospitals in the dataset are closed. We need to also filter these out before presenting the data.
hospitals %>%
filter(TYPE == "GENERAL ACUTE CARE" & STATUS == "OPEN") %>%
group_by(STATE) %>%
summarize(state_beds = sum(BEDS, na.rm = TRUE)) %>%
ungroup()
In other words, often times to answer questions within a dataset, we need to both zoom in and out on data - honing in on certan observations and then generalizing across them. We cannot answer questions well if we don’t have a good understanding of what’s included in our data and how issues are defined. Had we not known that hospitals that are closed and hospitals that are classed as rehabs or psychiatric facilities were included in the data, we may have made some poor assumptions about the number of beds available.
Also note how, in every step of data analysis, we have to make decisions about what to include and what to exclude in the analysis. Data analysts play a very active role in shaping the knowledge that gets produced from data. The numbers can never speak for themselves.
When I Need to Zoom In or Out
For some of you, these functions will be necessary to employ before performing operations across numeric variables in your dataset. This is because, as we learned last week, some of you have observational units that span multiple time periods, multiple geographies, or multiple issues. Before performing an operation across a numeric variable, we need to ensure all of the values in that variable are referring to observations reported across the same timeframe or geographic scale.
In the hospitals dataset, this is less of a concern because as we learned last week, the observational unit of the dataset is one thing without qualifiers - a hospital. The BEDS variable is always going to refer to the number of BEDS at a hospital.
With the world_health_econ data, we learned last week that every observation refers to a country and a year. Let’s say that we wanted to call summary() on life_exp variable to compare life expenctancies across countries. Without first zooming in to to a specific year, we would be including multiple values taken at the same place at different times. Let’s filter the data to only include the most recent reporting year and then call summary():
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>% #Note that this is how we can fliter to the rows with the maximum value in a variable; in this case, this would be the most recent year.
select(life_exp) %>%
summary()
life_exp
Min. :32.50
1st Qu.:63.95
Median :73.35
Mean :70.52
3rd Qu.:77.05
Max. :83.20
NA's :6
In rarer cases, we will need to group_by() and summarize() our data before statistically analyzing it. This is the case with the cases dataset. Each observation in the cases dataset refers to a combination of things - a province and a country. The issue is that not every country is reporting data at the province level. This means that sometimes the Total.Cases variable is referring to the number of cases in a country and sometimes it is referring to the number of cases in a Province. If we wanted to statistically analyze the number of cases across observations, we first need to transform the dataset so that each observation is reported at the same scale. In other words, we need to zoom out to standardize the observational unit across the dataset to the country level (since we do not always have data at the province level). To do that, we will need to group_by() Country.Region and then summarize the sum of Total.Cases.
cases %>%
group_by(Country.Region) %>%
summarize(Total.Cases = sum(Total.Cases, na.rm = TRUE)) %>%
ungroup()
Once we’ve done this, we can confidently statistically analyze the Total.Cases variable because we know that the number is always referring to the number of cases in a country.
Alternatively, we could also filter to one country to analyze numeric variables across provinces in that country. If I were to call summary() on the Total.Cases variable in the cases dataset, I would be gathering statistics across numbers reported at different geographic scales. Below, I filter the cases dataset to one Country - Canada - so that I’m gathering statistics across all provinces in Canada.
cases %>%
filter(Country.Region == "Canada") %>%
select(Total.Cases) %>%
summary()
Total.Cases
Min. : 0
1st Qu.: 16
Median : 206
Mean :1320
3rd Qu.:1526
Max. :5593
Let’s test the extent to which you will need to zoom in or zoom out to statistically analyze numeric values your data. Select a discrete numeric variable in your dataset. Now complete the statement below:
#Uncomment the last line below and fill in the blanks for your dataset.
#paste(df$DISCRETE_VARIABLE[1], "refers to a number of [FILL DISCRETE VARIABLE] in a _____ in my dataset.)
#Example:
paste(hospitals$BEDS[1], "refers to a number of beds in a hospital in my dataset.")
[1] "25 refers to a number of beds in a hospital in my dataset."
paste(world_health_econ$pop[1], "refers to a number of people in a country in a given year in my dataset.")
[1] "18100000 refers to a number of people in a country in a given year in my dataset."
paste(cases$Total.Cases[1], "refers to a number of cases in a country and/or province in my dataset.")
[1] "541 refers to a number of cases in a country and/or province in my dataset."
#paste(_____$_____[1], "refers to a number of _____ in a _____ in my dataset.)
How did you fill in the last _____? Is your observational unit one thing (e.g. one hospital, or one country)? If this is the case, it will likely not be as essential for you to zoom in or zoom out before operating on numeric variables. If so, we will say that you do not have qualified units of observation.
OR
Is your observational unit a combination of things or factors (e.g. one chemical reported at a particular facility or one census tract reporting in a particular year)? If this is the case, it will likely be essential for you to zoom in or zoom out before operating on numeric variables. If so, we will say that you do have qualified units of observation.
Are your units of observation qualified? If they are, do you expect to have to zoom in or zoom out on your data to perform operations across a numeric variable? What functions do you expect to use on what variables? Note: If you are struggling with this, please reach out to me.
Fill your response here.
Zooming in and/or Zooming Out on Your Own Data
Select one of the values that you identified from calling distinct() on a categorical variable in last week’s lab. Filter the dataset to the rows representing that value, select a numeric variable to explore, and then call summary(). If you have qualified units of observation, be sure to first zoom into a set of observations in your data (using filter()) or, in rarer cases, zoom out to generalize the observations (calling group_by(), summarize(), and ungroup()).
#Uncomment the appropriate lines below, and fill in your data frame, variables, and value.
#_____ %>% filter(_____ == "_____") %>% select(_____) %>% summary()
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from calling summary() on your filtered dataset?
Fill your response here.
Select a numeric variable in your dataset that represents the extent or scale of the issue you are studying. Pick a number that you believe serves as a good indicator that this issue is at a notable extent or scale, and filter the dataset to all the rows greater than (or less than) this number. Check the remaining distinct values in a categorical variable in the dataset. If you have qualified units of observation, be sure to first zoom into a set of observations in your data (using filter()) or, in rarer cases, zoom out to generalize the observations (calling group_by(), summarize(), and ungroup()).
#Uncomment the appropriate lines below, and fill in your data frame, variables, condition, and value.
#_____ %>% filter(_____ _____ _____) %>% distinct(_____)
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from calling distinct on the filtered data?
Fill your response here.
Select a categorical variable that you would like to group your data by, so that you can summarize some statistics across each grouping. You may group your data by a particular year, by a particular location (such as a state or a region), or by a particular category. Then select a numeric variable in your dataset to summarize by. For instance, you may want to sum the total number of reports in a given year, or find the average number of cases reported in a certain state.
#Uncomment the appropriate lines below, and fill in your data frame, variables, and summarize variable name, and math function.
#_____ %>% group_by(_____) %>% summarize(_____ = _____(_____, na.rm = TRUE)) %>% ungroup()
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from grouping and summarizing?
Fill your response here.
Combine any combination of the 4 verbs we learned in class this week or last (select, filter, group by, or summarize) to explore your dataset further. You may also use arrange, summary, or distinct.
#Fill your function here.
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from running this function?
Fill your response here.
Combine any combination of the 4 verbs we learned in class this week or last (select, filter, group by, or summarize) to explore your dataset further. You may also use arrange, summary, or distinct.
#Fill your function here.
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from running this function?
Fill your response here.
Variation
Variation is the extent to which the values that constitute a particular variable vary from observation to observation. Do we have a whole bunch of one particular value in a variable, and very few of another? Or maybe, do we have a more even distribution of values across a variable?
ggplot
At this point in the assignment, we will begin leveraging the Tidyverse package ggplot to create plots for visualizing the data. To create a plot with ggplot, we will follow this basic formula:
df %>%
ggplot(aes(x = VARIABLE_NAME)) +
CHART_TYPE
For example, for a bar chart, you will call:
df %>%
ggplot(aes(x = VARIABLE_NAME)) +
geom_bar()
For a column chart, you will call:
df %>%
ggplot(aes(x = VARIABLE_NAME, y = VARIABLE_NAME)) +
geom_col()
Let’s break that down a bit. First, as you have been doing with the dplyr package, you will call your dataframe. Following your dataframe and a pipe, you will call ggplot(), which basically tells R to prepare to create a plot. Inside ggplot, you will list aesthetics. These are variables in the dataset that you would like to appear on your plot. Setting x = VARIABLE_NAME tells ggplot() what variable to plot on the x-axis. Setting y = = VARIABLE_NAME tells ggplot() what variable to plot on the y-axis. Finally, following a plus (+) sign, you tell ggplot which type of plot to create. The ggplot cheatsheet lists a number of plots that you can create with ggplot, as well as a number of different ways to style the plot. We will practice several of these below.
For every plot that you produce, I will expect you to add a title and labels to the x and y axis. You can do this as follows:
df %>%
ggplot(aes(x = VARIABLE_NAME, y = VARIABLE_NAME)) +
geom_col() +
labs(title = "FILL TITLE", x = "FILL X-AXIS LABEL", y = "FILL Y-AXIS LABEL)
There are also a number of useful tools for styling your plots. For instance we can set the theme of the plot to look a bit more polished by adding “+ theme_bw()” to the plot.
df %>%
ggplot(aes(x = VARIABLE_NAME, y = VARIABLE_NAME)) +
geom_col() +
labs(title = "FILL TITLE", x = "FILL X-AXIS LABEL", y = "FILL Y-AXIS LABEL") +
theme_bw()
Two styling issues that I’m sure will come up in most of your plots include: * changing x or y axis tick numbers from scientific to comma notation: + scale_x_continuous(labels = scales::comma) OR + scale_y_continuous(labels = scales::comma) * turning x axis tick marks 90 degrees so that they do not overlap: + theme(axis.text.x = element_text(angle = 90, hjust=1)) OR + theme(axis.text.y = element_text(angle = 90, hjust=1))
df %>%
ggplot(aes(x = VARIABLE_NAME, y = VARIABLE_NAME)) +
geom_col() +
labs(title = "FILL TITLE", x = "FILL X-AXIS LABEL", y = "FILL Y-AXIS LABEL") +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Turn labels 90 degrees
scale_x_continuous(labels = scales::comma) #Change labels from scientific to comma notation
So how do we visualize variation with ggplot? Below I describe two different plots that you can leverage to visualize variation - a bar plot and a frequency plot.
Bar Plot
A bar plot displays the number of times each value appears in a categorial variable. This will tell us how the observations in the dataset vary in regards to that variable. In other words, this plot will communicate the number of observations in your dataset by that variable.
#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE)) + geom_bar() + labs(title = "TITLE", x = "X-AXIS NAME", y = "Y-AXIS NAME")
hospitals %>%
ggplot(aes(x = TYPE)) +
geom_bar() +
labs(title = "Number of Hospitals in the US by Type", x = "Type", y = "Count of Hospitals") + #Adds a title to the plot
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) #Changes x-axis tick labels 90 degrees

Remember that this dataset includes hospitals that are designated as closed. Depending on the question we are trying to address, we may wish to zoom in to only the observations signifying a hospital that is open before creating this plot.
#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE)) + geom_bar() + labs(title = "TITLE", x = "X-AXIS NAME", y = "Y-AXIS NAME")
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = TYPE)) +
geom_bar() +
labs(title = "Number of Hospitals in the US by Type", x = "Type", y = "Count of Hospitals") + #Adds a title to the plot
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) #Changes x-axis tick labels 90 degrees

Titling a Bar Plot
Note how I titled my first plot above: “Number of Hospitals in the US by Type” Remember last week, when we identified what makes each observation in our dataset unique? Here I am counting the observations by Type, and in order to know what I’m counting, I need to know what each observation refers to. A good formula for titling bar plots is as follows:
Number of _____ by [x-axis variable name]
In order to fill in the blank line above, consider the statement we produced last week: “I have nrow(df) unique _____ represented in my dataset.” That blank line told us what each observation in the dataset represented - or its observational unit. However we filled in that blank line should also be how we fill in the title of a bar plot.
The [x-axis variable name] should be your x-label and “Count of ______” (filled the same as above) should be your y-label. Note that if you filter your dataset, you should account for this in the title: “Number of Hospitals in the US by Type”
What if I have qualified units of observation?
If this is the case, then your y-axis is not counting a single thing like the number of hospitals, but a combination of things like the number of province/country pairs. For instance, let’s say your data reports the population of each country each year as it does in the world_health_econ dataset
Now let’s say that you wanted to plot the number of countries per continent. If you were to call:
world_health_econ %>%
ggplot(aes(x = continent)) +
geom_bar() +
labs(title = "Number of Countries per Continent", x = "Continent", y = "Count of Countries") + #Adds a title to the plot
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) #Changes x-axis tick labels 90 degrees

… you would be counting the combination of the number of countries and years per continent. Each country would be represented in the bar for every year that it was included in the dataset. In other words, the y-axis would not just represent countries but both countries and years. If we want the y-axis to only be counting one thing, then we need to first reduce the dataset to the distinct values of what you wish to count and what you wish to count by. You can do this by placing the distinct call before calling ggplot, or by filtering the data to the most recent year.
world_health_econ %>%
distinct(country, continent) %>%
ggplot(aes(x = continent)) +
geom_bar() +
labs(title = "Number of Countries per Continent", x = "Continent", y = "Count of Countries") + #Adds a title to the plot
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) #Changes x-axis tick labels 90 degrees

Select a categorical variable for which you want to visualize the frequency of times it appears in the dataset.
I recommend that you select one of the same categorical variables that you analyzed with the distinct() function last week. At this point hold off on selecting a geographic categorical variable, such as Country, State, or County. If you have qualified units of observation, be sure to reduce your dataset to the distinct values you wish to count.
#Uncomment the line below and fill appropriately. Add a title and labels to your plots, and adjust its style to be legible.
#_____ %>% ggplot(aes(x = _____)) + geom_bar()
#If qualified:
#_____ %>% distinct(_____) %>% ggplot(aes(x = _____)) + geom_bar()
Reflect on the distribution of categories in the dataset. Is there an even distribution of observations across each category, or are certain categories more represented than others? Why might this be? What does this say about the social, political, or economic landscape of your topic?
Fill response here.
Reflect on what you learned about the history of the categories you plotted above in last week’s lab. How have the social, political, and economic forces shaping this categorization impacted how we count observations related to this topic? How might this plot look different if this variable had been categorized in a different way?
Fill response here.
Frequency Plot
A frequency plot will display the distribution of values in a numeric variable within a designated set of increments. This will tell us how the observations in the dataset vary in regards to that variable. In other words, this plot will communicate the number of observations in your dataset broken down into increments of that variable.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE)) + geom_freqpoly(binwidth = 1) + labs(title = "TITLE", x = "X-AXIS NAME", y = "Y-AXIS NAME")
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = BEDS)) +
geom_freqpoly(binwidth = 10) +
labs(title = "Distribution of Beds across Hospitals in the US that are Open", x = "Beds", y = "Count of Hospitals") +
theme_bw()

Note that binwidth refers to the size of the increments at which frequency will be calculated. Above the binwidth is set to 10. This means that ggplot will display the frequency of each value at intervals of 10, 20, 30, 40, etc. When we set the bindwidth to 1, ggplot will display the frequency of each value at intervals of 1, 2, 3, 4. etc. What difference does this make?
Notice what happens when we set the binwidth to 1. While above we count the number of hospitals with 0-10 beds 10-20 beds, 20-30 beds, etc, this will count the number of hospitals with 0-1 beds, 1-2 beds, 2-3 beds, and so on. Because we are counting the number in such small increments, the plot will look much more jagged and will take a longer time to load. This plot displays the counts in finer granularity than the first plot.
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = BEDS)) +
geom_freqpoly(binwidth = 1) +
labs(title = "Distribution of Beds across Hospitals in the US that are Open", x = "Beds", y = "Count of Hospitals") +
theme_bw()
When we set the binwidth to 100, we count the number of hospitals with 0-100 beds, 100-200 beds, 200-300 beds, and so on. Because we are counting the number in larger increments, the plot will look much smoother and will take less time to load. This plot displays the counts in thicker granularity than the first plot.
hospitals %>%
ggplot(aes(x = BEDS)) +
geom_freqpoly(binwidth = 100) +
labs(title = "Distribution of Beds across Hospitals in the US", x = "Beds", y = "Count of Hospitals") +
theme_bw()

Titling a Frequency Plot
Note how I titled my plot above: “Distribution of Beds across Hospitals in the US that are Open” Consider again what makes each observation unique. A good formula for titling frequency plots is as follows:
Frequency of [x-axis variable name] across _____
Again, we can fill in the blank with our observational unit. The [x-axis variable name] should be your x-label and “Count of ______” (filled the same as above) should be your y-label.
What if I have qualified units of observation?
Let’s talk about what would happen if I were to make a frequency plot of the Total.Cases in the cases dataset:
cases %>%
ggplot(aes(x = Total.Cases)) +
geom_freqpoly(binwidth = 10000) +
labs(title = "Distribution of Cases across ____", x = "Total Cases", y = "Count of _____") + # To add titles and labels
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Turn labels 90 degrees
scale_x_continuous(labels = scales::comma) #Change labels from scientific to comma notation

We know that each observation in the cases dataset refers to a province/country pair. So here I’m counting the number of province/countries in each bracket of total cases. Since only some countries in this dataset are broken into provinces, we are comparing counts of cases across different geographic scales - sometimes at the province level and sometimes at the country level. In this case, it makes more sense to total up the number of cases per country and then plot the distribution of cases across countries. We can use group_by() and summarize() to do this:
cases %>%
group_by(Country.Region) %>%
summarize(Total.Cases = sum(Total.Cases, na.rm = TRUE)) %>%
ungroup() %>%
ggplot(aes(x = Total.Cases)) +
geom_freqpoly(binwidth = 10000) +
labs(title = "Distribution of Cases across Countries", x = "Total Cases", y = "Count of Countries") + # To add titles and labels
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Turn labels 90 degrees
scale_x_continuous(labels = scales::comma) #Change labels from scientific to comma notation

What about the world_health_econ data? Without separating out these units of observation, we would be visualizing multiple values reported at the same place at different periods in time (i.e. every year since 1995). Instead, we want to zoom into a single year in the dataset so we are just comparing values across place.
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>%
ggplot(aes(x = tot_health_sp_pp)) +
geom_freqpoly(binwidth = 100) +
labs(title = "Distribution of Total Health Spending per Person across Countries in 2010", x = "Total Health Spending per Person", y = "Count of Countries") + # To add titles and labels
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust=1)) + #Turn labels 90 degrees
scale_x_continuous(labels = scales::comma) #Change labels from scientific to comma notation

Note the addition to my title above. If you filter your dataset, the formula for titling changes a bit to Frequency of [x-axis variable name] across _____ in [filtered value]
Select a numeric variable for which you want to visualize the distribution of a set of values.
Be sure to select a variable that describes something about the observational unit and not another categorical variable in your dataset. For instance, let’s say you had the following data table - with each row reporting an environmental violation at a facility:
Violation Number | Facility Name | Facility Town | Population of Facility Town _________________ | _________________ | _________________ | _________________ 1234567 | Facility A | Tarrytown | 90000 2345678 | Facility B | Tarrytown | 90000 3456789 | Facility C | Another Town | 70000
In this table, we would not want to create a frequency plot with population of facility town. This is because our observational unit is a violation, not a town, and population does not describe something about the violation but instead describes something about the town the facility is in. If we were to create a frequency plot with this variable, we would be counting the number of times each population value appears in the dataset - something that does not make much sense, since we can have the same town’s population town appear several times in the dataset if there are more than violations or more than one facilities in a town.
If you have qualified units of observation, be sure to first zoom into a set of observations in your data (using filter()) or zoom out to generalize the observations (calling group_by(), summarize(), and ungroup()).
#Uncomment the line below and fill appropriately. Add a title and labels to your plots.
#_____ %>% ggplot(aes(x = _____)) + geom_freqpoly(binwidth = _____)
This gives us information about the distribution of values in the dataset. Reflect on the distribution of values. What are the range of values represented in the data? Are the values evenly distributed, or are certain values more represented than others? Why might this be? Do any of the values surprise you? Why?
Fill response here.
Why did you select the binwidth that you did? How might the story your plot tells change if you were to change the binwidth? What anomalies might be hidden with a larger binwidth, and what trends might be hidden with a smaller binwidth?
Fill response here.
Check how the numeric variable was defined in the data dictionary, and quote the defintion below. How might the counts represented in your frequency plot appear differently if this variable was defined differently?
Fill response here.
Produce two more plots that display variation. Continue to hold off on selecting a geographic categorical variable.
#Fill the code for plot 1 here. Add a title and labels to your plots.
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from this plot?
Fill your response here.
#Fill the code for plot 2 here. Add a title and labels to your plots.
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from this plot?
Fill your response here.
Co-variation
Co-variation is the extent to which the values that constitute two or more variables vary in relation to one another. To visualize co-variation, we might create:
Count Plots
Count plots display how many times two categorical values appear together in a dataset.
#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE, y = CATEGORICAL_VARIABLE)) + geom_count()
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = TYPE, y = OWNER)) +
geom_count() +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Number of Hospitals by Type and Ownership", x = "Type", y = "Ownership") + # To add titles and labels
theme_bw()

Titling a Count Plot
Note how I titled my plot above: “Number of Hospitals in the US that are Open by Type and Ownership” Consider again what makes each observation unique. Here I am counting the observations by Type and Ownership, and in order to know what I’m counting, I need to know what each observation refers to. A good formula for titling count plots is as follows:
Count of _____ by [x-axis variable name] and [y-axis variable name]
The blank should be filled with your unit of observation. The [x-axis variable name] should be your x-label and “Count of ______” (filled the same as above) should be your y-label.
What if I have qualified units of observation?
If this is the case I would encourage you to include one of the qualified variables in the x or y-axis. For instance if world_health_econ is qualified by country and year, I can include year as the y-axis below to visualize how counts of observations change over time. (Notice how they don’t in the plot below. )
world_health_econ %>%
ggplot(aes(x = continent, y = as.factor(year))) +
geom_count() +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Distribution of Total Health Spending per Person across Countries", x = "Continent", y = "Year") + # To add titles and labels
theme_bw()

Stacked Frequency Plots
Stacked frequency plots display the distribution of numeric values in a variable, grouped by a categorical value.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE, col = CATEGORICAL_VARIABLE)) + geom_freqpoly(binwidth = 1)
hospitals %>%
filter(STATUS == "OPEN") %>%
ggplot(aes(x = BEDS, col = TYPE)) +
geom_freqpoly(binwidth = 100) +
labs(title = "Frequency of Beds across Hospitals by Hospital Type", x = "Beds", y = "Count of Hospital", col = "Type") + # To add titles and labels
theme_bw()

Titling a Stacked Frequency Plot
Note how I titled my plot above: “Frequency of Beds across Hospitals in the US that are Open by Hospital Type” Consider again what makes each observation unique. Here I am counting the observations by number of Beds and Hospital Type. A good formula for titling stacked frequency plots is as follows:
Frequency of [x-axis variable name] across _____ by [col variable name]
The blank should be filled with your unit of observation. The [x-axis variable name] should be your x-label, “Count of ______” (filled the same as above) should be your y-label, and the [col variable name] should be your col-label.
What if I have qualified units of observation?
If this is the case I would encourage you to include one of the qualified variables in the col variable. For instance, if world_health_econ is qualified by country and year, I can include year as the col variable below to visualize how the frequency of countries with various life expectancies changes over time.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE, col = CATEGORICAL_VARIABLE)) + geom_freqpoly(binwidth = 1)
world_health_econ %>%
ggplot(aes(x = life_exp, col = as.factor(year))) +
geom_freqpoly(binwidth = 5) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Frequency of Life Expectancies across Countries by Year", x = "Life Expectancy", y = "Count of Countries", col = "Life Expectancy") + # To add titles and labels
theme_bw()

Note that this is one plot that is particularly susceptible to missing data. If certain countries did not report data in certain years, the count of countries in a bracket will appear lower, not necessarily because fewer countries fell within a certain life expectancy bracket, but because fewer countries reported that life expectancy.
Alternatively, you could zoom in to one value in one of your qualified variables, filtering to a specific subset of observations and then divide by a different categorical variable.
#df %>% ggplot(aes(x = NUMERIC_VARIABLE, col = CATEGORICAL_VARIABLE)) + geom_freqpoly(binwidth = 1)
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>%
ggplot(aes(x = life_exp, col = continent)) +
geom_freqpoly(binwidth = 5) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Frequency of Life Expectancies across Countries by Continent in 2010", x = "Life Expectancy", y = "Count of Countries", col = "Continent") + # To add titles and labels
theme_bw()

Point plots
Point plots display the relationship between a categorical variable and a numeric variable.
#df %>% ggplot(aes(x = CATEGORICAL_VARIABLE, y = NUMERIC_VARIABLE)) + geom_point()
hospitals %>%
ggplot(aes(x = TYPE, y = BEDS)) +
geom_point() +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Number of Beds in Hopsitals by Type", x = "Type", y = "Number of Beds") + # To add titles and labels
theme_bw()

# Note that the plot above exhibits overplotting - when the data represented on a plot overlaps, making it difficult to discern one point from the next. There are various tools available to deal with over-plotting. You can reduce the size of points on the plot, increase their transparency, or set them to slightly offset each other (known as adding jitter). We do all three below.
hospitals %>%
ggplot(aes(x = TYPE, y = BEDS)) +
geom_jitter(size = 0.5, alpha = 0.1) + #Change geom_point to geom_jitter, reduce the size, add transparency for overplotting
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Number of Beds in Hopsitals by Type", x = "Type", y = "Number of Beds") + # To add titles and labels
theme_bw()

Titling a Point Plot
Note how I titled my plot above: “Number of Beds in Hopsitals in the US that are Open by Type” Here I am displaying the number of beds by Type. A good formula for titling point plots is as follows:
Number/Measure of [y-axis variable name] in _____ by [x-axis variable name]
The blank should be filled with your unit of observation. The [x-axis variable name] should be your x-label and “Number/Measure of [y-axis variable name]” should be your y-label.
What if I have qualified units of observation?
If this is the case I would encourage you to filter your plot to one value in one of your qualified variables. For instance if world_health_econ is qualified by country and year, I can filter to the most recent year before creating a point plot of the private share of health spending by continent.
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>%
ggplot(aes(x = continent, y = priv_share_health_sp)) +
geom_point(size = 2, alpha = 0.8) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
labs(title = "Measure of Private Share of Health Spending in Countries by Continent in 2010", x = "Continent", y = "Measure of Private Share of Health Spending") + # To add titles and labels
theme_bw()

Scatterplots
Scatterplots display the relationship or correlation between two numeric variables.
#ggplot(df, aes(x = NUMERIC_VARIABLE, y = NUMERIC_VARIABLE)) + geom_point()
hospitals %>%
ggplot(aes(x = BEDS, y = POPULATION)) +
geom_point(size = 0.5) +
theme_bw() +
labs(title = "Relationship between Hospital Beds and Population", x = "Beds", y = "Population") + # To add titles and labels
theme_bw()

Note how this plot is particularly useful for finding outliers.
Titling a Scatterplot
Note how I titled my plot above: “Relationship between Hospital Beds and Population in the US” A good formula for titling scatterplots is as follows:
Relationship between _____ [x-axis variable name] and [y-axis variable name]
The blank should be filled with your unit of observation. The [x-axis variable name] should be your x-label and [y-axis variable name]" should be your y-label.
What if I have qualified units of observation?
If this is the case I would encourage you to filter your plot to one value in one of your qualified variables. For instance if world_health_econ is qualified by country and year, I can filter to the most recent year before creating a point plot of the private share of health spending by continent.
#ggplot(df, aes(x = NUMERIC_VARIABLE, y = NUMERIC_VARIABLE)) + geom_point()
world_health_econ %>%
filter(year == max(year, na.rm = TRUE)) %>%
ggplot(aes(x = tot_health_sp_pp, y = life_exp, size = pop, col = continent)) +
geom_point(shape = 21, stroke = 1) +
labs(title = "Relationship between Country Total Health Spending Per Person and Life Expectancy", x = "Total Health Spending Per Person", y = "Life Expectancy", size = "Population", col = "Continent") + # To add titles and labels
theme_bw() +
scale_size_continuous(range = c(1, 10), labels = scales::comma)

Produce four plots that represent co-variation in your dataset.
You need not include every plot I described above. At this point, please continue to hold off on selecting a geographic categorical variable. Be sure to zoom in or out on your data if you have qualified units of observation.
#Fill the code for plot 1 here. Add a title and labels to your plots. Be sure to adjust for overplotting.
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from this plot?
Fill your response here.
#Fill the code for plot 2 here. Add a title and labels to your plots. Be sure to adjust for overplotting.
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from this plot?
Fill your response here.
#Fill the code for plot 3 here. Add a title and labels to your plots. Be sure to adjust for overplotting.
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from this plot?
Fill your response here.
#Fill the code for plot 4 here. Add a title and labels to your plots. Be sure to adjust for overplotting.
What question might this analysis help to address?
Fill your response here.
Are there any other variables in your dataset that you need to take into consideration before directing this analysis towards answering that question? In other words, do you need to zoom into any specific areas of the dataset (by filtering) in order to appropriately address this question? If so, which? Be sure to adjust your plot above to reflect this.
Fill your response here.
What insight can you draw from this plot?
Fill your response here.
Start a shiny app.
At this point in the quarter, we are prepared to start piecing together a dashboard for displaying the data. Shiny Apps have two components - a front end (ui), and a backend (server). On the front end, we will be coding how we want our data displayed. For this week, the only thing you need to do on the front end is fill in your title. On the backend, we will be coding our data analysis.
Fill in your title in the UI.
ui <- dashboardPage(
dashboardHeader(title = "TITLE HERE"),
dashboardSidebar(
#inputs will go here.
),
dashboardBody(
box(plotOutput("plot1")),
box(plotOutput("plot2"))
)
)
Replace my plots in the code below with two of the plots that you created in this lab.
server <- function(input, output, session) {
output$plot1 <- renderPlot({
hospitals %>% ggplot(aes(x = TYPE)) + geom_bar()
#Replace plot above with your own plot.
})
output$plot2 <- renderPlot({
hospitals %>% ggplot(aes(x = TYPE)) + geom_bar()
#Replace plot above with your own plot.
})
}
shinyApp(ui, server)
Listening on http://127.0.0.1:6195
NA
When you knit this notebook, you will get a prompt asking whether you would prefer to render and run this document as Shiny. Click No. We will be leaving this notebook in a GitHub document format.
LS0tCnRpdGxlOiAiTGFiIDUgLSBEYXRhIFZhcmlhdGlvbiBhbmQgQ28tVmFyaWF0aW9uIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogeWVzCiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogJzMnCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgojIyBJbnN0cnVjdGlvbnMgYW5kIE92ZXJ2aWV3CgpJbiB0aGlzIGFzc2lnbm1lbnQsIHdlIHdpbGwgcHJhY3RpY2UgZ3JhcGhpY2FsbHkgcmVwcmVzZW50aW5nIHZhcmlhdGlvbiBhbmQgY292YXJpYXRpb24gaW4gYSBkYXRhc2V0LiBUbyBiZWdpbiB5b3Ugd2lsbCBuZWVkIHRvIGltcG9ydCBhbmQgY2xlYW4geW91ciBkYXRhc2V0LiBZb3UgbWF5IHJlZmVyZW5jZSBsYXN0IHdlZWsncyBsYWIgdG8gaGVscCB3aXRoIHRoaXMuIEFmdGVyIHRoaXMsIHlvdSBzaG91bGQgZm9sbG93IHRoZSBwcm9tcHRzIGFuZCBjb21wbGV0ZSB0aGUgc2hvcnQgYW5zd2VyIHF1ZXN0aW9ucy4gQXQgdmFyaW91cyBwb2ludHMgaW4gdGhpcyBhc3NpZ25tZW50LCB5b3Ugd2lsbCBiZSBhc2tlZCB0byBkcmF3IGluc2lnaHRzIGFib3V0IHlvdXIgZGF0YXNldCBhZnRlciBjYWxsaW5nIGNlcnRhaW4gZnVuY3Rpb25zLiBXaGVuIEkgYXNrIHlvdSB0byBkcmF3IGFuIGluc2lnaHQsIEnigJltIG5vdCBhc2tpbmcgeW91IHRvIGRlc2NyaWJlIHdoYXQgdGhlIGZ1bmN0aW9uIGRvZXMgb3IgdG8gc3RhdGUgdGhlIHJlc3VsdHMgdGhhdCB5b3UgZ2V0LiBJbnN0ZWFkIEnigJltIGFza2luZyB5b3UgdG8gaW50ZXJwcmV0IHRob3NlIHJlc3VsdHMgYW5kIGNvbnNpZGVyIHdoYXQgdGhpcyBtaWdodCB0ZWxsIHVzIGFib3V0IHRoZSBpc3N1ZXMgcmVwcmVzZW50ZWQgaW4gdGhlIGRhdGFzZXQgb3IgaWYgaXQgbWlnaHQgc2lnbmFsIGlzc3VlcyBvZiBkYXRhIHF1YWxpdHkuIEZvciBpbnN0YW5jZSwgc3RhdGluZyDigJx0aGUgbWF4aW11bSB2YWx1ZSBpbiB0aGUgYWdlIGNvbHVtbiBpcyA5OTks4oCdIGlzIG5vdCBhbiBpbnNpZ2h0LiBJbnN0ZWFkIHlvdSBzaG91bGQgc2F5LCDigJx0aGUgbWF4aW11bSB2YWx1ZSBpbiB0aGUgYWdlIGNvbHVtbiBpcyA5OTksIHdoaWNoIGlzIG11Y2ggaGlnaGVyIHRoYW4gSSB3b3VsZCBleHBlY3QgYW5kIG1heSBzaWduYWwgdGhhdCB0aGUgZGF0YSB3YXMgaW5wdXQgd3Jvbmcgb3IgdGhhdCB0aGUgZGF0YSBjb2xsZWN0b3JzIGF0IHVzaW5nIDk5OSB0byByZXByZXNlbnQgbnVsbCB2YWx1ZXMu4oCdCgojIyBHZXR0aW5nIFN0YXJ0ZWQKCiMjIyBMb2FkIHRoZSByZWxldmFudCBsaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShzaGlueSkKbGlicmFyeShzaGlueWRhc2hib2FyZCkKYGBgCgojIyMgSW1wb3J0IGFuZCBjbGVhbiBleGFtcGxlIGRhdGFzZXRzIApgYGB7cn0KaG9zcGl0YWxzIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbGluZHNheXBvaXJpZXIvU1RTLTExNS9tYXN0ZXIvZGF0YXNldHMvSG9zcGl0YWxzLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCndvcmxkX2hlYWx0aF9lY29uIDwtIHJlYWQuY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbGluZHNheXBvaXJpZXIvU1RTLTExNS9tYXN0ZXIvZGF0YXNldHMvd29ybGRfaGVhbHRoX2Vjb24uY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKY2FzZXMgPC0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9DU1NFR0lTYW5kRGF0YS9DT1ZJRC0xOS9tYXN0ZXIvY3NzZV9jb3ZpZF8xOV9kYXRhL2Nzc2VfY292aWRfMTlfdGltZV9zZXJpZXMvdGltZV9zZXJpZXNfY292aWQxOV9jb25maXJtZWRfZ2xvYmFsLmNzdiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKCiNEbyBub3Qgd29ycnkgYWJvdXQgdGhpcyBsaW5lIG9mIGNvZGUgZm9yIG5vdy4gU2luY2UgdGhlIGNhc2VzIGRhdGEgZ2V0cyBhcHBlbmRlZCBldmVyeSBkYXkgd2l0aCBhIG5ldyBjb2x1bW4gcmVwcmVzZW50aW5nIHRoYXQgZGF5J3MgY2FzZSBjb3VudHMsIGlmIHdlIHdhbnQgdGhlIHRvdGFsIGNhc2VzIHBlciBjb3VudHJ5LCB3ZSBuZWVkIHRvIGFkZCB1cCBhbGwgb2YgdGhlIHByZXZpb3VzIGRheSdzIGNvdW50cyBpbnRvIGEgbmV3IGNvbHVtbi4gVGhlIGNvbHVtbiBiZWxvdyBkb2VzIHRoaXMgZm9yIHVzLiAKY2FzZXMgPC0gCiAgY2FzZXMgJT4lIAogIG11dGF0ZShUb3RhbC5DYXNlcyA9IAogICAgICAgICAgIGNhc2VzICU+JSAKICAgICAgICAgICBzZWxlY3Qoc3RhcnRzX3dpdGgoIlgiKSkgJT4lIAogICAgICAgICAgIHJvd1N1bXMoKQogICAgICAgICApICU+JQogIHNlbGVjdChQcm92aW5jZS5TdGF0ZSwgQ291bnRyeS5SZWdpb24sIFRvdGFsLkNhc2VzKQoKaG9zcGl0YWxzJFpJUCA8LSBhcy5jaGFyYWN0ZXIoaG9zcGl0YWxzJFpJUCkKCmhvc3BpdGFscyRaSVAgPC0gc3RyX3BhZChob3NwaXRhbHMkWklQLCA1LCBwYWQgPSAiMCIpIAoKaXMubmEoaG9zcGl0YWxzKSA8LSBob3NwaXRhbHMgPT0gIk5PVCBBVkFJTEFCTEUiCmlzLm5hKGhvc3BpdGFscykgPC0gaG9zcGl0YWxzID09IC05OTkKaXMubmEoY2FzZXMpIDwtIGNhc2VzID09ICIiCgpob3NwaXRhbHMkU09VUkNFREFURSA8LSB5bWRfaG1zKGhvc3BpdGFscyRTT1VSQ0VEQVRFKQpob3NwaXRhbHMkVkFMX0RBVEUgPC0geW1kX2htcyhob3NwaXRhbHMkVkFMX0RBVEUpCgpgYGAKCiMjIyBJbXBvcnQgYW5kIGNsZWFuIHlvdXIgZGF0YXNldC4gCmBgYHtyfQojQ29weSBhbmQgcGFzdGUgcmVsZXZhbnQgY29kZSBmcm9tIExhYiA0IHRvIGltcG9ydCB5b3VyIGRhdGEgaGVyZS4gCgojQ29weSBhbmQgcGFzdGUgcmVsZXZhbnQgY29kZSBmcm9tIExhYiA0IHRvIGNsZWFuIHlvdXIgZGF0YSBoZXJlLiBUaGlzIGluY2x1ZGVzIGFueSByb3cgYmluZGluZywgY2hhcmFjdGVyIHJlbW92YWxzLCBjb252ZXJpb25zIGluIHZhcmlhYmxlIHR5cGUsIGRhdGUgZm9ybWF0dGluZywgb3IgTkEgY29udmVyc2lvbnMuIApgYGAKCiMjIEV4cGxvcmluZyBTdWJzZXR0ZWQgb3IgR3JvdXBlZCBEYXRhCgpMYXN0IHdlZWssIHdlIGV4cGxvcmVkIGhvdyB5b3VyIGRhdGEgd2FzIGRlZmluZWQsIGhvdyBpdCB3YXMgY2F0ZWdvcml6ZWQsIGFuZCBob3cgbWlzc2luZyB2YWx1ZXMgd2VyZSByZXByZXNlbnRlZC4gVGhyb3VnaCB0aGlzIGV4ZXJjaXNlLCB3ZSB3ZXJlIGFibGUgdG8gZGV2ZWxvcCBhIGdvb2QgZ2VuZXJhbCBvdmVydmlldyBvZiB0aGUgb2JzZXJ2YXRpb25zLCB2YXJpYWJsZXMsIGFuZCB2YWx1ZXMgaW4gb3VyIGRhdGFzZXRzLiBTb21ldGltZXMsIGhvd2V2ZXIsIHdlIHdhbnQgdG8gYmUgYWJsZSB0byB6b29tIGluIHRvIHNwZWNpZmljIGFyZWFzIG9mIG91ciBkYXRhc2V0IGFuZCBleHBsb3JlIHdoYXQgaXMgZ29pbmcgb24gaW4gdGhhdCBhcmVhLiBXZSBhbHNvIHNvbWV0aW1lcyB3YW50IHRvIGJlIGFibGUgdG8gem9vbSBvdXQgLSBzdW1tYXJpemluZyBzb21ldGhpbmcgYWNyb3NzIGdyb3VwcyBvZiBvYnNlcnZhdGlvbnMgaW4gb3VyIGRhdGEuICBBcyB3ZSBwcmVwYXJlIHRvIHZpc3VhbGl6ZSB2YXJpYXRpb24gYW5kIGNvLXZhcmlhdGlvbiBpbiB0aGUgZGF0YXNldCwgbGV0J3MgZmlyc3QgZ28gb3ZlciBob3cgd2UgY2FuIGJvdGggem9vbSBpbiBhbmQgem9vbSBvdXQgb24gb3VyIGRhdGFzZXRzLiAKCiMjIyBab29taW5nIGluIC0gRXhwbG9yaW5nIEZpbHRlcmVkIENhdGVnb3JpY2FsIERhdGEKCiMjIyMgRmlsdGVyaW5nIHRvIGEgQ2F0ZWdvcnkKCkZpbHRlcmluZyBpcyBvbmUgd2F5IHdlIGNhbiB6b29tIGluIG9uIG91ciBkYXRhIC0gZXhwbG9yaW5nIG9ubHkgdGhvc2Ugb2JzZXJ2YXRpb25zIHRoYXQgbWVldCBhIHBhcnRpY3VsYXIgY3JpdGVyaWEuCgpGb3IgaW5zdGFuY2UsIGxhc3Qgd2VlayB3ZSBsZWFybmVkIGFib3ZlIHRoYXQgb25lIGNyaXRlcmlhIGZvciBiZWluZyBkZXNpZ25hdGVkIGFzIGEgQ3JpdGljYWwgQWNjZXNzIEhvc3BpdGFsIGlzIHRoYXQgdGhlIGhvc3BpdGFsIG11c3QgaGF2ZSAyNSBvciBmZXdlciBpbnBhdGllbnQgYmVkcy4gV2UgbWF5IHdhbnQgdG8gc2VlIGhvdyB0aGUgdmFsdWVzIGZvciBCRURTIGNoYW5nZSB3aGVuIHdlIGZpbHRlciB0byAob3Igem9vbSBpbnRvKSBqdXN0IHRob3NlIG9ic2VydmF0aW9ucyByZXByZXNlbnRpbmcgY3JpdGljYWwgYWNjZXNzIGhvc3BpdGFscy4gQmVsb3cgSSB3aWxsIGRvIHRoaXMsIHNlbGVjdCB0aGUgQkVEUyB2YXJpYWJsZSwgYW5kIGNhbGwgc3VtbWFyeSgpLgoKYGBge3J9CiNkZiAlPiUgZmlsdGVyKENBVEVHT1JJQ0FMX1ZBUklBQkxFID09ICJWQUxVRSIpICU+JSBzZWxlY3QoTlVNRVJJQ19WQVJJQUJMRSkgJT4lIHN1bW1hcnkoKSAKaG9zcGl0YWxzICU+JSBmaWx0ZXIoVFlQRSA9PSAiQ1JJVElDQUwgQUNDRVNTIikgJT4lIHNlbGVjdChCRURTKSAlPiUgc3VtbWFyeSgpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZXJlIGFyZSBzb21lIGhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBoYXZlIGJlZW4gZGVzaWduYXRlZCBhcyBjcml0aWNhbCBhY2Nlc3MgaG9zcGl0YWxzIHRoYXQgaGF2ZSBtb3JlIHRoYW4gMjUgYmVkcy4gU2luY2UgdGhpcyBkb2VzIG5vdCBhbGlnbiB3aXRoIHRoZSBjcml0ZXJpYSBmb3IgY3JpdGljYWwgYWNjZXNzIGhvc3BpdGFscyB0aGF0IHdlIGRpc2NvdmVyZWQgaW4gb3VyIHJlc2VhcmNoLCBpdCBpcyBsaWtlbHkgc29tZXRoaW5nIHRoYXQgd2Ugd2lsbCB3YW50IHRvIGludmVzdGlnYXRlIGZ1cnRoZXIuCgojIyMjIEZpbHRlcmluZyB0byBOdW1lcmljIE9ic2VydmF0aW9ucyBBYm92ZSBvciBCZWxvdyBhIFRocmVzaG9sZAoKV2UgbWF5IGFsc28gd2FudCB0byBzZWUgd2hpY2ggc3RhdGVzIGhhdmUgaG9zcGl0YWxzIHdpdGggbW9yZSB0aGFuIDE1MDAgYmVkcy4gVG8gZG8gc28sIHdlIHdvdWxkIGZpbHRlciB0aGUgZGF0YSB0byB0aG9zZSBvYnNlcnZhdGlvbnMgd2hlcmUgQkVEUyBpcyBncmVhdGVyIHRoYW4gMTUwMCwgYW5kIHRoZW4gd2Ugd291bGQgY2hlY2sgdGhlIGRpc3RpbmN0KCkgU1RBVEVTIHJlbWFpbmluZyBpbiB0aGUgZGF0YS4KCmBgYHtyfQojZGYgJT4lIGZpbHRlcihOVU1CRVJJQ19WQVJJQUJMRSA+IFZBTFVFKSAlPiUgZGlzdGluY3QoQ0FURUdPUklDQUxfVkFSSUFCTEUpCmhvc3BpdGFscyAlPiUgZmlsdGVyKEJFRFMgPiAxNTAwKSAlPiUgZGlzdGluY3QoU1RBVEUpCmBgYAoKRnJvbSB0aGlzIGV4ZXJjaXNlLCB3ZSBjYW4gc2VlIHRoYXQgb25seSB0d28gc3RhdGVzIGhhdmUgaG9zcGl0YWxzIHdpdGggbW9yZSB0aGFuIDE1MDAgYmVkcyBhdmFpbGFibGUuCgojIyMgWm9vbWluZyBvdXQgLSBha2EgZ3JvdXBpbmcgY29tbW9uIHZhbHVlcyBhbmQgc3VtbWFyaXppbmcKCkF0IHRpbWVzLCB3ZSBhcmUgc2Vla2luZyB0byBnZXQgYSBicm9hZGVyIHBpY3R1cmUgb2Ygd2hhdCdzIGdvaW5nIG9uIGluIG91ciBkYXRhc2V0IHRoYW4gcHJvdmlkZWQgLSBncm91cGluZyBvYnNlcnZhdGlvbnMgdGhhdCBzaGFyZSBhIGNvbW1vbiB2YWx1ZSBhbmQgdGhlbiBwZXJmb3JtaW5nIGEgY2FsY3VsYXRpb24gdG8gc3VtbWFyaXplIHNvbWV0aGluZyB3aXRoaW4gZWFjaCBvZiB0aG9zZSBncm91cHMuIEZvciBpbnN0YW5jZSwgSSBtYXkgd2FudCB0byBrbm93IHRoZSB0b3RhbCBudW1iZXIgb2YgaG9zcGl0YWwgYmVkcyBwZXIgc3RhdGUuIFRvIGNhbGN1bGF0ZSB0aGlzLCBJIHdvdWxkIG5lZWQgdG8gZ3JvdXAgYWxsIG9mIHRoZSBob3NwaXRhbCBvYnNlcnZhdGlvbnMgYnkgc3RhdGUgYW5kIHRoZW4gc3VtIHRoZSB0b3RhbCBudW1iZXIgb2YgYmVkcyBpbiBlYWNoIGdyb3VwLiAKCkluIHN1Y2ggY2FzZXMsIHdlIGNhbiBjYWxsICoqZ3JvdXBfYnkoKSoqIHRvIGFnZ3JlZ2F0ZSB0aGUgb2JzZXJ2YXRpb25zIHdpdGggY29tbW9uIHZhcmlhYmxlIHZhbHVlcyBpbnRvIGdyb3Vwcy4gVGhlbiB3ZSB3aWxsIGNhbGwgKipzdW1tYXJpemUoKSoqIHRvIHBlcmZvcm0gYSBjYWxjdWxhdGlvbiB3aXRoaW4gZWFjaCBvZiB0aG9zZSBncm91cHMuICoqc3VtbWFyaXplKCkqKiB0YWtlcyBhIHNldCBvZiB2YWx1ZXMgYW5kIGEgY2FsY3VsYXRpb24gbWV0aG9kIGFuZCByZXR1cm5zIGEgc2luZ2xlIHZhbHVlLiBGb3IgaW5zdGFuY2UsIGlmIHdlIGNhbGwgc3VtbWFyaXplKCkgd2l0aCBhIG51bWVyaWMgY29sdW1uIGluIG91ciBkYXRhc2V0IGFuZCAibWVhbiIgYXMgYSBjYWxjdWxhdGlvbiBtZXRob2QsIGl0IHdpbGwgcmV0dXJuIHRoZSBhdmVyYWdlIG9mIGFsbCB0aGUgbnVtZXJpYyB2YWx1ZXMgaW4gdGhhdCBjb2x1bW4uIFdoZW4gY2FsbGVkIGluIGNvbmp1bmN0aW9uIHdpdGggZ3JvdXBfYnkoKSwgaXQgdGFrZXMgYSBzZXQgb2YgdmFsdWVzIGZvciBlYWNoIGdyb3VwIGFuZCBhIGNhbGN1bGF0aW9uIG1ldGhvZCBhbmQgcmV0dXJucyBhIHNpbmdsZSB2YWx1ZSBmb3IgZWFjaCBncm91cC4gCgpGb3IgdGhlIGhvc3BpdGFscyBkYXRhc2V0LCB3ZSB3aWxsIGdyb3VwIHRoZSBvYnNlcnZhdGlvbnMgYnkgU1RBVEUgYW5kIHRoZW4gdXNlIHN1bW1hcml6ZSB0byBjYWxjdWxhdGUgdGhlIHN1bSBvZiBCRURTIHBlciBzdGF0ZS4gCgpgYGB7cn0KI2RmICU+JSBncm91cF9ieShDQVRFR09SSUNBTF9WQVJJQUJMRSkgJT4lIHN1bW1hcml6ZShORVdfVkFSSUFCTEVfTkFNRSA9IHN1bShOVU1CRVJJQ19WQVJJQUJMRSwgbmEucm0gPSBUUlVFKSkgJT4lIHVuZ3JvdXAoKQpob3NwaXRhbHMgJT4lIGdyb3VwX2J5KFNUQVRFKSAlPiUgc3VtbWFyaXplKHN0YXRlX2JlZHMgPSBzdW0oQkVEUywgbmEucm0gPSBUUlVFKSkgJT4lIHVuZ3JvdXAoKQpgYGAKCj4gTm90aWNlIHRoYXQgSSBjbG9zZSBlYWNoIG9mIHRoZXNlIGNhbGxzIHdpdGggKip1bmdyb3VwKCkqKi4gV2hlbiB3ZSBncm91cF9ieSgpIGEgdmFyaWFibGUsIGFueSBzdWJzZXF1ZW50IGZ1bmN0aW9uIGNhbGxzIHdpbGwgY29udGludWUgdG8gYmUgcGVyZm9ybWVkIG9uIHRoZSBncm91cGVkIGRhdGEsIHVubGVzcyB3ZSB1bmdyb3VwKCkgaXQuIFRoaXMgY2FuIGJlIGltcG9ydGFudCBpZiB3ZSB3YW50IHRvIGZpbHRlciB0byBzcGVjaWZpYyB2YWx1ZXMgYWZ0ZXIgd2Ugc3VtbWFyaXplKCkgdGhlIGRhdGEuIEFzc3VtaW5nIHRoYXQgd2UgZG9uJ3Qgd2FudCB0byBwZXJmb3JtIGEgZmlsdGVyIG9wZXJhdGlvbiB3aXRoaW4gZWFjaCBncm91cCBidXQgb24gdGhlIGVudGlyZSBuZXcgZGF0YWZyYW1lIGNyZWF0ZWQgYWZ0ZXIgc3VtbWFyaXppbmcsIHdlIG5lZWQgdG8gdW5ncm91cCgpIHRoZSBkYXRhIGJlZm9yZSBwZXJmb3JtaW5nIHRoZSBmaWx0ZXIoKSBvcGVyYXRpb24uIAoKPiBOb3RlIGhvdyB3ZSBhcmUgY2hvb3NpbmcgdG8gaWdub3JlIE5BIHZhbHVlcyBhYm92ZSBieSBjYWxsaW5nIG5hLnJtID0gVFJVRS4gV2hlbiB3ZSBkbyBzbywgd2UgbmVlZCB0byBrZWVwIGluIG1pbmQgdGhhdCB3ZSBhcmUgbm90IHN1bW1hcml6aW5nIGFjcm9zcyBhbGwgb2JzZXJ2YXRpb25zIGluIHRoZSBkYXRhc2V0LCBidXQgb25seSB0aG9zZSBmb3Igd2hpY2ggdGhlcmUgaXMgYSB2YWx1ZSBsaXN0ZWQgaW4gdGhlIHZhcmlhYmxlIHdlIGFyZSBvcGVyYXRpbmcgb24uIFdoeSBtaWdodCBpdCBiZSBpbXBvcnRhbnQgdG8gbWFrZSBjb21tdW5pY2F0ZSB0aGF0IHdlJ3ZlIG1hZGUgdGhpcyBtb3ZlIHdoZW4gd2UgYXJlIHByZXNlbnRpbmcgb3VyIGRhdGE/CgpGcm9tIHRoaXMgZnVuY3Rpb24sIHdlIHNlZSB0aGUgbnVtYmVyIG9mIGJlZHMgYWNyb3NzIGFsbCBob3NwaXRhbHMgcGVyIHN0YXRlLiBEZXBlbmRpbmcgb24gdGhlIHF1ZXN0aW9uIHdlIGFyZSBhc2tpbmcsIHRoaXMgbWF5IG9yIG1heSBub3QgYmUgcmVsZXZhbnQuIEZvciBpbnN0YW5jZSwgaWYgSSdtIHdvbmRlcmluZyBob3cgbXVjaCBob3NwaXRhbCBpbmZyYXN0cnVjdHVyZSBpcyBhdmFpbGFibGUgdG8gc3VwcG9ydCBDb3ZpZC0xOSBwYXRpZW50cywgb25lIChvZiBhIG51bWJlciBvZiBmYWN0b3JzKSBJIG5lZWQgdG8gY29uc2lkZXIgYmVmb3JlIHByZXNlbnRpbmcgdGhpcyBkYXRhIGlzIHdoaWNoIHR5cGVzIG9mIGhvc3BpdGFscyBhcmUgYWNjZXB0aW5nIENvdmlkLTE5IHBhdGllbnRzLiBBcmUgcmVoYWJpbGl0YXRpb24gaG9zcGl0YWxzIGFjY2VwdGluZyBwYXRpZW50cz8gUHN5Y2hpYXRyaWMgaG9zcGl0YWxzPyBNaWxpdGFyeSBob3NwaXRhbHM/IElmIHRoZXkgYXJlbid0IG5vdywgd2lsbCB0aGV5IGF0IHNvbWUgcG9pbnQ/IEZ1cnRoZXIsIHNvbWUgc3RhdGVzIGFyZSB0YWxraW5nIGFib3V0IGNvcmRvbmluZyBvZmYgaG90ZWxzIGZvciBDb3ZpZC0xOSBwYXRpZW50cy4gSG93IGRvIHdlIGFjY291bnQgZm9yIHRoaXMgY2hhbmdlIGluIHRoZSBudW1iZXIgb2YgaG9zcGl0YWwgYmVkcyAoc29tZXRoaW5nIGRlZmluaXRlbHkgbm90IHJlcHJlc2VudGVkIGluIG91ciBkYXRhIGJhc2VkIG9uIHRoZSB3YXkgaG9zcGl0YWwgaGFzIGJlZW4gZGVmaW5lZCkuIFdlIG5lZWQgdG8gZG8gZXh0ZXJuYWwgcmVzZWFyY2ggdG8gYW5zd2VyIHRoZXNlIHF1ZXN0aW9ucy4gVGhlbiB3ZSBtYXkgd2lzaCB0byBmaWx0ZXIgb3VyIGRhdGEgdG8gcmVsZXZhbnQgaG9zcGl0YWwgdHlwZXMuIEZvciBpbnN0YW5jZSwgYXQgdGhpcyBtb21lbnQsIHdlIG1heSBmaWx0ZXIgb3VyIGRhdGEgdG8gb25seSBpbmNsdWRlIGJlZHMgYXQgR2VuZXJhbCBBY3V0ZSBDYXJlIEhvc3BpdGFscy4gV2UgYWxzbyBrbm93IHRoYXQgc29tZSBob3NwaXRhbHMgaW4gdGhlIGRhdGFzZXQgYXJlIGNsb3NlZC4gV2UgbmVlZCB0byBhbHNvIGZpbHRlciB0aGVzZSBvdXQgYmVmb3JlIHByZXNlbnRpbmcgdGhlIGRhdGEuIAoKYGBge3J9Cmhvc3BpdGFscyAlPiUKICBmaWx0ZXIoVFlQRSA9PSAiR0VORVJBTCBBQ1VURSBDQVJFIiAmIFNUQVRVUyA9PSAiT1BFTiIpICU+JQogIGdyb3VwX2J5KFNUQVRFKSAlPiUgCiAgc3VtbWFyaXplKHN0YXRlX2JlZHMgPSBzdW0oQkVEUywgbmEucm0gPSBUUlVFKSkgJT4lIAogIHVuZ3JvdXAoKQpgYGAKCkluIG90aGVyIHdvcmRzLCBvZnRlbiB0aW1lcyB0byBhbnN3ZXIgcXVlc3Rpb25zIHdpdGhpbiBhIGRhdGFzZXQsIHdlIG5lZWQgdG8gYm90aCB6b29tIGluIGFuZCBvdXQgb24gZGF0YSAtIGhvbmluZyBpbiBvbiBjZXJ0YW4gb2JzZXJ2YXRpb25zIGFuZCB0aGVuIGdlbmVyYWxpemluZyBhY3Jvc3MgdGhlbS4gV2UgY2Fubm90IGFuc3dlciBxdWVzdGlvbnMgd2VsbCBpZiB3ZSBkb24ndCBoYXZlIGEgZ29vZCB1bmRlcnN0YW5kaW5nIG9mIHdoYXQncyBpbmNsdWRlZCBpbiBvdXIgZGF0YSBhbmQgaG93IGlzc3VlcyBhcmUgZGVmaW5lZC4gSGFkIHdlIG5vdCBrbm93biB0aGF0IGhvc3BpdGFscyB0aGF0IGFyZSBjbG9zZWQgYW5kIGhvc3BpdGFscyB0aGF0IGFyZSBjbGFzc2VkIGFzIHJlaGFicyBvciBwc3ljaGlhdHJpYyBmYWNpbGl0aWVzIHdlcmUgaW5jbHVkZWQgaW4gdGhlIGRhdGEsIHdlIG1heSBoYXZlIG1hZGUgc29tZSBwb29yIGFzc3VtcHRpb25zIGFib3V0IHRoZSBudW1iZXIgb2YgYmVkcyBhdmFpbGFibGUuCgpBbHNvIG5vdGUgaG93LCBpbiBldmVyeSBzdGVwIG9mIGRhdGEgYW5hbHlzaXMsIHdlIGhhdmUgdG8gbWFrZSBkZWNpc2lvbnMgYWJvdXQgd2hhdCB0byBpbmNsdWRlIGFuZCB3aGF0IHRvIGV4Y2x1ZGUgaW4gdGhlIGFuYWx5c2lzLiBEYXRhIGFuYWx5c3RzIHBsYXkgYSB2ZXJ5IGFjdGl2ZSByb2xlIGluIHNoYXBpbmcgdGhlIGtub3dsZWRnZSB0aGF0IGdldHMgcHJvZHVjZWQgZnJvbSBkYXRhLiBUaGUgbnVtYmVycyBjYW4gbmV2ZXIgc3BlYWsgZm9yIHRoZW1zZWx2ZXMuIAoKIyMjIFdoZW4gSSBOZWVkIHRvIFpvb20gSW4gb3IgT3V0CgpGb3Igc29tZSBvZiB5b3UsIHRoZXNlIGZ1bmN0aW9ucyB3aWxsIGJlIG5lY2Vzc2FyeSB0byBlbXBsb3kgYmVmb3JlIHBlcmZvcm1pbmcgb3BlcmF0aW9ucyBhY3Jvc3MgbnVtZXJpYyB2YXJpYWJsZXMgaW4geW91ciBkYXRhc2V0LiBUaGlzIGlzIGJlY2F1c2UsIGFzIHdlIGxlYXJuZWQgbGFzdCB3ZWVrLCBzb21lIG9mIHlvdSBoYXZlIG9ic2VydmF0aW9uYWwgdW5pdHMgdGhhdCBzcGFuIG11bHRpcGxlIHRpbWUgcGVyaW9kcywgbXVsdGlwbGUgZ2VvZ3JhcGhpZXMsIG9yIG11bHRpcGxlIGlzc3Vlcy4gQmVmb3JlIHBlcmZvcm1pbmcgYW4gb3BlcmF0aW9uIGFjcm9zcyBhIG51bWVyaWMgdmFyaWFibGUsIHdlIG5lZWQgdG8gZW5zdXJlIGFsbCBvZiB0aGUgdmFsdWVzIGluIHRoYXQgdmFyaWFibGUgYXJlIHJlZmVycmluZyB0byBvYnNlcnZhdGlvbnMgcmVwb3J0ZWQgYWNyb3NzIHRoZSBzYW1lIHRpbWVmcmFtZSBvciBnZW9ncmFwaGljIHNjYWxlLgoKSW4gdGhlIGhvc3BpdGFscyBkYXRhc2V0LCB0aGlzIGlzIGxlc3Mgb2YgYSBjb25jZXJuIGJlY2F1c2UgYXMgd2UgbGVhcm5lZCBsYXN0IHdlZWssIHRoZSBvYnNlcnZhdGlvbmFsIHVuaXQgb2YgdGhlIGRhdGFzZXQgaXMgb25lIHRoaW5nIHdpdGhvdXQgcXVhbGlmaWVycyAtIGEgaG9zcGl0YWwuIFRoZSBCRURTIHZhcmlhYmxlIGlzIGFsd2F5cyBnb2luZyB0byByZWZlciB0byB0aGUgbnVtYmVyIG9mIEJFRFMgYXQgYSBob3NwaXRhbC4KCldpdGggdGhlIHdvcmxkX2hlYWx0aF9lY29uIGRhdGEsIHdlIGxlYXJuZWQgbGFzdCB3ZWVrIHRoYXQgZXZlcnkgb2JzZXJ2YXRpb24gcmVmZXJzIHRvIGEgY291bnRyeSBhbmQgYSB5ZWFyLiBMZXQncyBzYXkgdGhhdCB3ZSB3YW50ZWQgdG8gY2FsbCBzdW1tYXJ5KCkgb24gbGlmZV9leHAgdmFyaWFibGUgdG8gY29tcGFyZSBsaWZlIGV4cGVuY3RhbmNpZXMgYWNyb3NzIGNvdW50cmllcy4gV2l0aG91dCBmaXJzdCB6b29taW5nIGluIHRvIHRvIGEgc3BlY2lmaWMgeWVhciwgd2Ugd291bGQgYmUgaW5jbHVkaW5nIG11bHRpcGxlIHZhbHVlcyB0YWtlbiBhdCB0aGUgc2FtZSBwbGFjZSBhdCBkaWZmZXJlbnQgdGltZXMuIExldCdzIGZpbHRlciB0aGUgZGF0YSB0byBvbmx5IGluY2x1ZGUgdGhlIG1vc3QgcmVjZW50IHJlcG9ydGluZyB5ZWFyIGFuZCB0aGVuIGNhbGwgc3VtbWFyeSgpOgoKYGBge3J9CndvcmxkX2hlYWx0aF9lY29uICU+JQogIGZpbHRlcih5ZWFyID09IG1heCh5ZWFyLCBuYS5ybSA9IFRSVUUpKSAlPiUgI05vdGUgdGhhdCB0aGlzIGlzIGhvdyB3ZSBjYW4gZmxpdGVyIHRvIHRoZSByb3dzIHdpdGggdGhlIG1heGltdW0gdmFsdWUgaW4gYSB2YXJpYWJsZTsgaW4gdGhpcyBjYXNlLCB0aGlzIHdvdWxkIGJlIHRoZSBtb3N0IHJlY2VudCB5ZWFyLiAKICBzZWxlY3QobGlmZV9leHApICU+JQogIHN1bW1hcnkoKQpgYGAKCkluIHJhcmVyIGNhc2VzLCB3ZSB3aWxsIG5lZWQgdG8gZ3JvdXBfYnkoKSBhbmQgc3VtbWFyaXplKCkgb3VyIGRhdGEgYmVmb3JlIHN0YXRpc3RpY2FsbHkgYW5hbHl6aW5nIGl0LiBUaGlzIGlzIHRoZSBjYXNlIHdpdGggdGhlIGNhc2VzIGRhdGFzZXQuIEVhY2ggb2JzZXJ2YXRpb24gaW4gdGhlIGNhc2VzIGRhdGFzZXQgcmVmZXJzIHRvIGEgY29tYmluYXRpb24gb2YgdGhpbmdzIC0gYSBwcm92aW5jZSBhbmQgYSBjb3VudHJ5LiBUaGUgaXNzdWUgaXMgdGhhdCBub3QgZXZlcnkgY291bnRyeSBpcyByZXBvcnRpbmcgZGF0YSBhdCB0aGUgcHJvdmluY2UgbGV2ZWwuIFRoaXMgbWVhbnMgdGhhdCBzb21ldGltZXMgdGhlIFRvdGFsLkNhc2VzIHZhcmlhYmxlIGlzIHJlZmVycmluZyB0byB0aGUgbnVtYmVyIG9mIGNhc2VzIGluIGEgY291bnRyeSBhbmQgc29tZXRpbWVzIGl0IGlzIHJlZmVycmluZyB0byB0aGUgbnVtYmVyIG9mIGNhc2VzIGluIGEgUHJvdmluY2UuIElmIHdlIHdhbnRlZCB0byBzdGF0aXN0aWNhbGx5IGFuYWx5emUgdGhlIG51bWJlciBvZiBjYXNlcyBhY3Jvc3Mgb2JzZXJ2YXRpb25zLCB3ZSBmaXJzdCBuZWVkIHRvIHRyYW5zZm9ybSB0aGUgZGF0YXNldCBzbyB0aGF0IGVhY2ggb2JzZXJ2YXRpb24gaXMgcmVwb3J0ZWQgYXQgdGhlIHNhbWUgc2NhbGUuIEluIG90aGVyIHdvcmRzLCB3ZSBuZWVkIHRvIHpvb20gb3V0IHRvIHN0YW5kYXJkaXplIHRoZSBvYnNlcnZhdGlvbmFsIHVuaXQgYWNyb3NzIHRoZSBkYXRhc2V0IHRvIHRoZSBjb3VudHJ5IGxldmVsIChzaW5jZSB3ZSBkbyBub3QgYWx3YXlzIGhhdmUgZGF0YSBhdCB0aGUgcHJvdmluY2UgbGV2ZWwpLiBUbyBkbyB0aGF0LCB3ZSB3aWxsIG5lZWQgdG8gZ3JvdXBfYnkoKSBDb3VudHJ5LlJlZ2lvbiBhbmQgdGhlbiBzdW1tYXJpemUgdGhlIHN1bSBvZiBUb3RhbC5DYXNlcy4KCmBgYHtyfQpjYXNlcyAlPiUKICBncm91cF9ieShDb3VudHJ5LlJlZ2lvbikgJT4lCiAgc3VtbWFyaXplKFRvdGFsLkNhc2VzID0gc3VtKFRvdGFsLkNhc2VzLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkKYGBgCk9uY2Ugd2UndmUgZG9uZSB0aGlzLCB3ZSBjYW4gY29uZmlkZW50bHkgc3RhdGlzdGljYWxseSBhbmFseXplIHRoZSBUb3RhbC5DYXNlcyB2YXJpYWJsZSBiZWNhdXNlIHdlIGtub3cgdGhhdCB0aGUgbnVtYmVyIGlzIGFsd2F5cyByZWZlcnJpbmcgdG8gdGhlIG51bWJlciBvZiBjYXNlcyBpbiBhIGNvdW50cnkuCgpBbHRlcm5hdGl2ZWx5LCB3ZSBjb3VsZCBhbHNvIGZpbHRlciB0byBvbmUgY291bnRyeSB0byBhbmFseXplIG51bWVyaWMgdmFyaWFibGVzIGFjcm9zcyBwcm92aW5jZXMgaW4gdGhhdCBjb3VudHJ5LiBJZiBJIHdlcmUgdG8gY2FsbCBzdW1tYXJ5KCkgb24gdGhlIFRvdGFsLkNhc2VzIHZhcmlhYmxlIGluIHRoZSBjYXNlcyBkYXRhc2V0LCBJIHdvdWxkIGJlIGdhdGhlcmluZyBzdGF0aXN0aWNzIGFjcm9zcyBudW1iZXJzIHJlcG9ydGVkIGF0IGRpZmZlcmVudCBnZW9ncmFwaGljIHNjYWxlcy4gQmVsb3csIEkgZmlsdGVyIHRoZSBjYXNlcyBkYXRhc2V0IHRvIG9uZSBDb3VudHJ5IC0gQ2FuYWRhIC0gc28gdGhhdCBJJ20gZ2F0aGVyaW5nIHN0YXRpc3RpY3MgYWNyb3NzIGFsbCBwcm92aW5jZXMgaW4gQ2FuYWRhLiAKCmBgYHtyfQpjYXNlcyAlPiUgCiAgZmlsdGVyKENvdW50cnkuUmVnaW9uID09ICJDYW5hZGEiKSAlPiUKICBzZWxlY3QoVG90YWwuQ2FzZXMpICU+JQogIHN1bW1hcnkoKQpgYGAKCkxldCdzIHRlc3QgdGhlIGV4dGVudCB0byB3aGljaCB5b3Ugd2lsbCBuZWVkIHRvIHpvb20gaW4gb3Igem9vbSBvdXQgdG8gc3RhdGlzdGljYWxseSBhbmFseXplIG51bWVyaWMgdmFsdWVzIHlvdXIgZGF0YS4gU2VsZWN0IGEgZGlzY3JldGUgbnVtZXJpYyB2YXJpYWJsZSBpbiB5b3VyIGRhdGFzZXQuIE5vdyBjb21wbGV0ZSB0aGUgc3RhdGVtZW50IGJlbG93OgoKYGBge3J9CiNVbmNvbW1lbnQgdGhlIGxhc3QgbGluZSBiZWxvdyBhbmQgZmlsbCBpbiB0aGUgYmxhbmtzIGZvciB5b3VyIGRhdGFzZXQuIAojcGFzdGUoZGYkRElTQ1JFVEVfVkFSSUFCTEVbMV0sICJyZWZlcnMgdG8gYSBudW1iZXIgb2YgW0ZJTEwgRElTQ1JFVEUgVkFSSUFCTEVdIGluIGEgX19fX18gaW4gbXkgZGF0YXNldC4pCgojRXhhbXBsZToKcGFzdGUoaG9zcGl0YWxzJEJFRFNbMV0sICJyZWZlcnMgdG8gYSBudW1iZXIgb2YgYmVkcyBpbiBhIGhvc3BpdGFsIGluIG15IGRhdGFzZXQuIikKcGFzdGUod29ybGRfaGVhbHRoX2Vjb24kcG9wWzFdLCAicmVmZXJzIHRvIGEgbnVtYmVyIG9mIHBlb3BsZSBpbiBhIGNvdW50cnkgaW4gYSBnaXZlbiB5ZWFyIGluIG15IGRhdGFzZXQuIikKcGFzdGUoY2FzZXMkVG90YWwuQ2FzZXNbMV0sICJyZWZlcnMgdG8gYSBudW1iZXIgb2YgY2FzZXMgaW4gYSBjb3VudHJ5IGFuZC9vciBwcm92aW5jZSBpbiBteSBkYXRhc2V0LiIpCgojcGFzdGUoX19fX18kX19fX19bMV0sICJyZWZlcnMgdG8gYSBudW1iZXIgb2YgX19fX18gaW4gYSBfX19fXyBpbiBteSBkYXRhc2V0LikKYGBgCkhvdyBkaWQgeW91IGZpbGwgaW4gdGhlIGxhc3QgX19fX18/IApJcyB5b3VyIG9ic2VydmF0aW9uYWwgdW5pdCBvbmUgdGhpbmcgKGUuZy4gb25lIGhvc3BpdGFsLCBvciBvbmUgY291bnRyeSk/IElmIHRoaXMgaXMgdGhlIGNhc2UsIGl0IHdpbGwgbGlrZWx5IG5vdCBiZSBhcyBlc3NlbnRpYWwgZm9yIHlvdSB0byB6b29tIGluIG9yIHpvb20gb3V0IGJlZm9yZSBvcGVyYXRpbmcgb24gbnVtZXJpYyB2YXJpYWJsZXMuICoqSWYgc28sIHdlIHdpbGwgc2F5IHRoYXQgeW91IGRvIG5vdCBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbi4qKgoKT1IgCgpJcyB5b3VyIG9ic2VydmF0aW9uYWwgdW5pdCBhIGNvbWJpbmF0aW9uIG9mIHRoaW5ncyBvciBmYWN0b3JzIChlLmcuIG9uZSBjaGVtaWNhbCByZXBvcnRlZCBhdCBhIHBhcnRpY3VsYXIgZmFjaWxpdHkgb3Igb25lIGNlbnN1cyB0cmFjdCByZXBvcnRpbmcgaW4gYSBwYXJ0aWN1bGFyIHllYXIpPyBJZiB0aGlzIGlzIHRoZSBjYXNlLCBpdCB3aWxsIGxpa2VseSBiZSBlc3NlbnRpYWwgZm9yIHlvdSB0byB6b29tIGluIG9yIHpvb20gb3V0IGJlZm9yZSBvcGVyYXRpbmcgb24gbnVtZXJpYyB2YXJpYWJsZXMuICoqSWYgc28sIHdlIHdpbGwgc2F5IHRoYXQgeW91IGRvIGhhdmUgcXVhbGlmaWVkIHVuaXRzIG9mIG9ic2VydmF0aW9uLioqCgpBcmUgeW91ciB1bml0cyBvZiBvYnNlcnZhdGlvbiBxdWFsaWZpZWQ/IElmIHRoZXkgYXJlLCBkbyB5b3UgZXhwZWN0IHRvIGhhdmUgdG8gem9vbSBpbiBvciB6b29tIG91dCBvbiB5b3VyIGRhdGEgdG8gcGVyZm9ybSBvcGVyYXRpb25zIGFjcm9zcyBhIG51bWVyaWMgdmFyaWFibGU/IFdoYXQgZnVuY3Rpb25zIGRvIHlvdSBleHBlY3QgdG8gdXNlIG9uIHdoYXQgdmFyaWFibGVzPyBOb3RlOiBJZiB5b3UgYXJlIHN0cnVnZ2xpbmcgd2l0aCB0aGlzLCBwbGVhc2UgcmVhY2ggb3V0IHRvIG1lLgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKIyMjIFpvb21pbmcgaW4gYW5kL29yIFpvb21pbmcgT3V0IG9uIFlvdXIgT3duIERhdGEKClNlbGVjdCBvbmUgb2YgdGhlIHZhbHVlcyB0aGF0IHlvdSBpZGVudGlmaWVkIGZyb20gY2FsbGluZyBkaXN0aW5jdCgpIG9uIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgaW4gbGFzdCB3ZWVrJ3MgbGFiLiBGaWx0ZXIgdGhlIGRhdGFzZXQgdG8gdGhlIHJvd3MgcmVwcmVzZW50aW5nIHRoYXQgdmFsdWUsIHNlbGVjdCBhIG51bWVyaWMgdmFyaWFibGUgdG8gZXhwbG9yZSwgYW5kIHRoZW4gY2FsbCBzdW1tYXJ5KCkuIElmIHlvdSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbiwgYmUgc3VyZSB0byBmaXJzdCB6b29tIGludG8gYSBzZXQgb2Ygb2JzZXJ2YXRpb25zIGluIHlvdXIgZGF0YSAodXNpbmcgZmlsdGVyKCkpIG9yLCBpbiByYXJlciBjYXNlcywgem9vbSBvdXQgdG8gZ2VuZXJhbGl6ZSB0aGUgb2JzZXJ2YXRpb25zIChjYWxsaW5nIGdyb3VwX2J5KCksIHN1bW1hcml6ZSgpLCBhbmQgdW5ncm91cCgpKS4KYGBge3J9CiNVbmNvbW1lbnQgdGhlIGFwcHJvcHJpYXRlIGxpbmVzIGJlbG93LCBhbmQgZmlsbCBpbiB5b3VyIGRhdGEgZnJhbWUsIHZhcmlhYmxlcywgYW5kIHZhbHVlLiAKI19fX19fICU+JSBmaWx0ZXIoX19fX18gPT0gIl9fX19fIikgJT4lIHNlbGVjdChfX19fXykgJT4lIHN1bW1hcnkoKQpgYGAKCldoYXQgcXVlc3Rpb24gbWlnaHQgdGhpcyBhbmFseXNpcyBoZWxwIHRvIGFkZHJlc3M/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKQXJlIHRoZXJlIGFueSBvdGhlciB2YXJpYWJsZXMgaW4geW91ciBkYXRhc2V0IHRoYXQgeW91IG5lZWQgdG8gdGFrZSBpbnRvIGNvbnNpZGVyYXRpb24gYmVmb3JlIGRpcmVjdGluZyB0aGlzIGFuYWx5c2lzIHRvd2FyZHMgYW5zd2VyaW5nIHRoYXQgcXVlc3Rpb24/IEluIG90aGVyIHdvcmRzLCBkbyB5b3UgbmVlZCB0byB6b29tIGludG8gYW55IHNwZWNpZmljIGFyZWFzIG9mIHRoZSBkYXRhc2V0IChieSBmaWx0ZXJpbmcpIGluIG9yZGVyIHRvIGFwcHJvcHJpYXRlbHkgYWRkcmVzcyB0aGlzIHF1ZXN0aW9uPyBJZiBzbywgd2hpY2g/IEJlIHN1cmUgdG8gYWRqdXN0IHlvdXIgcGxvdCBhYm92ZSB0byByZWZsZWN0IHRoaXMuCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKV2hhdCBpbnNpZ2h0IGNhbiB5b3UgZHJhdyBmcm9tIGNhbGxpbmcgc3VtbWFyeSgpIG9uIHlvdXIgZmlsdGVyZWQgZGF0YXNldD8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpTZWxlY3QgYSBudW1lcmljIHZhcmlhYmxlIGluIHlvdXIgZGF0YXNldCB0aGF0IHJlcHJlc2VudHMgdGhlIGV4dGVudCBvciBzY2FsZSBvZiB0aGUgaXNzdWUgeW91IGFyZSBzdHVkeWluZy4gUGljayBhIG51bWJlciB0aGF0IHlvdSBiZWxpZXZlIHNlcnZlcyBhcyBhIGdvb2QgaW5kaWNhdG9yIHRoYXQgdGhpcyBpc3N1ZSBpcyBhdCBhIG5vdGFibGUgZXh0ZW50IG9yIHNjYWxlLCBhbmQgZmlsdGVyIHRoZSBkYXRhc2V0IHRvIGFsbCB0aGUgcm93cyBncmVhdGVyIHRoYW4gKG9yIGxlc3MgdGhhbikgdGhpcyBudW1iZXIuIENoZWNrIHRoZSByZW1haW5pbmcgZGlzdGluY3QgdmFsdWVzIGluIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgaW4gdGhlIGRhdGFzZXQuIElmIHlvdSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbiwgYmUgc3VyZSB0byBmaXJzdCB6b29tIGludG8gYSBzZXQgb2Ygb2JzZXJ2YXRpb25zIGluIHlvdXIgZGF0YSAodXNpbmcgZmlsdGVyKCkpIG9yLCBpbiByYXJlciBjYXNlcywgem9vbSBvdXQgdG8gZ2VuZXJhbGl6ZSB0aGUgb2JzZXJ2YXRpb25zIChjYWxsaW5nIGdyb3VwX2J5KCksIHN1bW1hcml6ZSgpLCBhbmQgdW5ncm91cCgpKS4gCgpgYGB7cn0KI1VuY29tbWVudCB0aGUgYXBwcm9wcmlhdGUgbGluZXMgYmVsb3csIGFuZCBmaWxsIGluIHlvdXIgZGF0YSBmcmFtZSwgdmFyaWFibGVzLCBjb25kaXRpb24sIGFuZCB2YWx1ZS4gCiNfX19fXyAlPiUgZmlsdGVyKF9fX19fIF9fX19fIF9fX19fKSAlPiUgZGlzdGluY3QoX19fX18pCmBgYAoKV2hhdCBxdWVzdGlvbiBtaWdodCB0aGlzIGFuYWx5c2lzIGhlbHAgdG8gYWRkcmVzcz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpBcmUgdGhlcmUgYW55IG90aGVyIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGFzZXQgdGhhdCB5b3UgbmVlZCB0byB0YWtlIGludG8gY29uc2lkZXJhdGlvbiBiZWZvcmUgZGlyZWN0aW5nIHRoaXMgYW5hbHlzaXMgdG93YXJkcyBhbnN3ZXJpbmcgdGhhdCBxdWVzdGlvbj8gSW4gb3RoZXIgd29yZHMsIGRvIHlvdSBuZWVkIHRvIHpvb20gaW50byBhbnkgc3BlY2lmaWMgYXJlYXMgb2YgdGhlIGRhdGFzZXQgKGJ5IGZpbHRlcmluZykgaW4gb3JkZXIgdG8gYXBwcm9wcmlhdGVseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IElmIHNvLCB3aGljaD8gQmUgc3VyZSB0byBhZGp1c3QgeW91ciBwbG90IGFib3ZlIHRvIHJlZmxlY3QgdGhpcy4KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpXaGF0IGluc2lnaHQgY2FuIHlvdSBkcmF3IGZyb20gY2FsbGluZyBkaXN0aW5jdCBvbiB0aGUgZmlsdGVyZWQgZGF0YT8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpTZWxlY3QgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSB0aGF0IHlvdSB3b3VsZCBsaWtlIHRvIGdyb3VwIHlvdXIgZGF0YSBieSwgc28gdGhhdCB5b3UgY2FuIHN1bW1hcml6ZSBzb21lIHN0YXRpc3RpY3MgYWNyb3NzIGVhY2ggZ3JvdXBpbmcuIFlvdSBtYXkgZ3JvdXAgeW91ciBkYXRhIGJ5IGEgcGFydGljdWxhciB5ZWFyLCBieSBhIHBhcnRpY3VsYXIgbG9jYXRpb24gKHN1Y2ggYXMgYSBzdGF0ZSBvciBhIHJlZ2lvbiksIG9yIGJ5IGEgcGFydGljdWxhciBjYXRlZ29yeS4gVGhlbiBzZWxlY3QgYSBudW1lcmljIHZhcmlhYmxlIGluIHlvdXIgZGF0YXNldCB0byBzdW1tYXJpemUgYnkuIEZvciBpbnN0YW5jZSwgeW91IG1heSB3YW50IHRvIHN1bSB0aGUgdG90YWwgbnVtYmVyIG9mIHJlcG9ydHMgaW4gYSBnaXZlbiB5ZWFyLCBvciBmaW5kIHRoZSBhdmVyYWdlIG51bWJlciBvZiBjYXNlcyByZXBvcnRlZCBpbiBhIGNlcnRhaW4gc3RhdGUuIAoKYGBge3J9CiNVbmNvbW1lbnQgdGhlIGFwcHJvcHJpYXRlIGxpbmVzIGJlbG93LCBhbmQgZmlsbCBpbiB5b3VyIGRhdGEgZnJhbWUsIHZhcmlhYmxlcywgYW5kIHN1bW1hcml6ZSB2YXJpYWJsZSBuYW1lLCBhbmQgbWF0aCBmdW5jdGlvbi4gCiNfX19fXyAlPiUgZ3JvdXBfYnkoX19fX18pICU+JSBzdW1tYXJpemUoX19fX18gPSBfX19fXyhfX19fXywgbmEucm0gPSBUUlVFKSkgJT4lIHVuZ3JvdXAoKQpgYGAKCldoYXQgcXVlc3Rpb24gbWlnaHQgdGhpcyBhbmFseXNpcyBoZWxwIHRvIGFkZHJlc3M/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKQXJlIHRoZXJlIGFueSBvdGhlciB2YXJpYWJsZXMgaW4geW91ciBkYXRhc2V0IHRoYXQgeW91IG5lZWQgdG8gdGFrZSBpbnRvIGNvbnNpZGVyYXRpb24gYmVmb3JlIGRpcmVjdGluZyB0aGlzIGFuYWx5c2lzIHRvd2FyZHMgYW5zd2VyaW5nIHRoYXQgcXVlc3Rpb24/IEluIG90aGVyIHdvcmRzLCBkbyB5b3UgbmVlZCB0byB6b29tIGludG8gYW55IHNwZWNpZmljIGFyZWFzIG9mIHRoZSBkYXRhc2V0IChieSBmaWx0ZXJpbmcpIGluIG9yZGVyIHRvIGFwcHJvcHJpYXRlbHkgYWRkcmVzcyB0aGlzIHF1ZXN0aW9uPyBJZiBzbywgd2hpY2g/IEJlIHN1cmUgdG8gYWRqdXN0IHlvdXIgcGxvdCBhYm92ZSB0byByZWZsZWN0IHRoaXMuCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKV2hhdCBpbnNpZ2h0IGNhbiB5b3UgZHJhdyBmcm9tIGdyb3VwaW5nIGFuZCBzdW1tYXJpemluZz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpDb21iaW5lIGFueSBjb21iaW5hdGlvbiBvZiB0aGUgNCB2ZXJicyB3ZSBsZWFybmVkIGluIGNsYXNzIHRoaXMgd2VlayBvciBsYXN0IChzZWxlY3QsIGZpbHRlciwgZ3JvdXAgYnksIG9yIHN1bW1hcml6ZSkgdG8gZXhwbG9yZSB5b3VyIGRhdGFzZXQgZnVydGhlci4gWW91IG1heSBhbHNvIHVzZSBhcnJhbmdlLCBzdW1tYXJ5LCBvciBkaXN0aW5jdC4gCgpgYGB7cn0KI0ZpbGwgeW91ciBmdW5jdGlvbiBoZXJlLiAKYGBgCgpXaGF0IHF1ZXN0aW9uIG1pZ2h0IHRoaXMgYW5hbHlzaXMgaGVscCB0byBhZGRyZXNzPwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCkFyZSB0aGVyZSBhbnkgb3RoZXIgdmFyaWFibGVzIGluIHlvdXIgZGF0YXNldCB0aGF0IHlvdSBuZWVkIHRvIHRha2UgaW50byBjb25zaWRlcmF0aW9uIGJlZm9yZSBkaXJlY3RpbmcgdGhpcyBhbmFseXNpcyB0b3dhcmRzIGFuc3dlcmluZyB0aGF0IHF1ZXN0aW9uPyBJbiBvdGhlciB3b3JkcywgZG8geW91IG5lZWQgdG8gem9vbSBpbnRvIGFueSBzcGVjaWZpYyBhcmVhcyBvZiB0aGUgZGF0YXNldCAoYnkgZmlsdGVyaW5nKSBpbiBvcmRlciB0byBhcHByb3ByaWF0ZWx5IGFkZHJlc3MgdGhpcyBxdWVzdGlvbj8gSWYgc28sIHdoaWNoPyBCZSBzdXJlIHRvIGFkanVzdCB5b3VyIHBsb3QgYWJvdmUgdG8gcmVmbGVjdCB0aGlzLgoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCldoYXQgaW5zaWdodCBjYW4geW91IGRyYXcgZnJvbSBydW5uaW5nIHRoaXMgZnVuY3Rpb24/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKQ29tYmluZSBhbnkgY29tYmluYXRpb24gb2YgdGhlIDQgdmVyYnMgd2UgbGVhcm5lZCBpbiBjbGFzcyB0aGlzIHdlZWsgb3IgbGFzdCAoc2VsZWN0LCBmaWx0ZXIsIGdyb3VwIGJ5LCBvciBzdW1tYXJpemUpIHRvIGV4cGxvcmUgeW91ciBkYXRhc2V0IGZ1cnRoZXIuIFlvdSBtYXkgYWxzbyB1c2UgYXJyYW5nZSwgc3VtbWFyeSwgb3IgZGlzdGluY3QuIAoKYGBge3J9CiNGaWxsIHlvdXIgZnVuY3Rpb24gaGVyZS4gCmBgYAoKV2hhdCBxdWVzdGlvbiBtaWdodCB0aGlzIGFuYWx5c2lzIGhlbHAgdG8gYWRkcmVzcz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpBcmUgdGhlcmUgYW55IG90aGVyIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGFzZXQgdGhhdCB5b3UgbmVlZCB0byB0YWtlIGludG8gY29uc2lkZXJhdGlvbiBiZWZvcmUgZGlyZWN0aW5nIHRoaXMgYW5hbHlzaXMgdG93YXJkcyBhbnN3ZXJpbmcgdGhhdCBxdWVzdGlvbj8gSW4gb3RoZXIgd29yZHMsIGRvIHlvdSBuZWVkIHRvIHpvb20gaW50byBhbnkgc3BlY2lmaWMgYXJlYXMgb2YgdGhlIGRhdGFzZXQgKGJ5IGZpbHRlcmluZykgaW4gb3JkZXIgdG8gYXBwcm9wcmlhdGVseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IElmIHNvLCB3aGljaD8gQmUgc3VyZSB0byBhZGp1c3QgeW91ciBwbG90IGFib3ZlIHRvIHJlZmxlY3QgdGhpcy4KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpXaGF0IGluc2lnaHQgY2FuIHlvdSBkcmF3IGZyb20gcnVubmluZyB0aGlzIGZ1bmN0aW9uPwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCiMjIFZhcmlhdGlvbgoKVmFyaWF0aW9uIGlzIHRoZSBleHRlbnQgdG8gd2hpY2ggdGhlIHZhbHVlcyB0aGF0IGNvbnN0aXR1dGUgYSBwYXJ0aWN1bGFyIHZhcmlhYmxlIHZhcnkgZnJvbSBvYnNlcnZhdGlvbiB0byBvYnNlcnZhdGlvbi4gRG8gd2UgaGF2ZSBhIHdob2xlIGJ1bmNoIG9mIG9uZSBwYXJ0aWN1bGFyIHZhbHVlIGluIGEgdmFyaWFibGUsIGFuZCB2ZXJ5IGZldyBvZiBhbm90aGVyPyBPciBtYXliZSwgZG8gd2UgaGF2ZSBhIG1vcmUgZXZlbiBkaXN0cmlidXRpb24gb2YgdmFsdWVzIGFjcm9zcyBhIHZhcmlhYmxlPwoKIyMjIGdncGxvdAoKQXQgdGhpcyBwb2ludCBpbiB0aGUgYXNzaWdubWVudCwgd2Ugd2lsbCBiZWdpbiBsZXZlcmFnaW5nIHRoZSBUaWR5dmVyc2UgcGFja2FnZSAqKmdncGxvdCoqIHRvIGNyZWF0ZSBwbG90cyBmb3IgdmlzdWFsaXppbmcgdGhlIGRhdGEuIFRvIGNyZWF0ZSBhIHBsb3Qgd2l0aCBnZ3Bsb3QsIHdlIHdpbGwgZm9sbG93IHRoaXMgYmFzaWMgZm9ybXVsYToKCmBgYHtyIGV2YWw9RkFMU0V9CmRmICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBWQVJJQUJMRV9OQU1FKSkgKyAKICBDSEFSVF9UWVBFCmBgYAoKRm9yIGV4YW1wbGUsIGZvciBhIGJhciBjaGFydCwgeW91IHdpbGwgY2FsbDoKCmBgYHtyIGV2YWw9RkFMU0V9CmRmICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBWQVJJQUJMRV9OQU1FKSkgKyAKICBnZW9tX2JhcigpCmBgYAoKRm9yIGEgY29sdW1uIGNoYXJ0LCB5b3Ugd2lsbCBjYWxsOgoKYGBge3IgZXZhbD1GQUxTRX0KZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IFZBUklBQkxFX05BTUUsIHkgPSBWQVJJQUJMRV9OQU1FKSkgKyAKICBnZW9tX2NvbCgpCmBgYAogIApMZXQncyBicmVhayB0aGF0IGRvd24gYSBiaXQuIEZpcnN0LCBhcyB5b3UgaGF2ZSBiZWVuIGRvaW5nIHdpdGggdGhlICoqZHBseXIqKiBwYWNrYWdlLCB5b3Ugd2lsbCBjYWxsIHlvdXIgZGF0YWZyYW1lLiBGb2xsb3dpbmcgeW91ciBkYXRhZnJhbWUgYW5kIGEgcGlwZSwgeW91IHdpbGwgY2FsbCBnZ3Bsb3QoKSwgd2hpY2ggYmFzaWNhbGx5IHRlbGxzIFIgdG8gcHJlcGFyZSB0byBjcmVhdGUgYSBwbG90LiBJbnNpZGUgZ2dwbG90LCB5b3Ugd2lsbCBsaXN0ICphZXN0aGV0aWNzKi4gVGhlc2UgYXJlIHZhcmlhYmxlcyBpbiB0aGUgZGF0YXNldCB0aGF0IHlvdSB3b3VsZCBsaWtlIHRvIGFwcGVhciBvbiB5b3VyIHBsb3QuIFNldHRpbmcgeCA9IFZBUklBQkxFX05BTUUgdGVsbHMgZ2dwbG90KCkgd2hhdCB2YXJpYWJsZSB0byBwbG90IG9uIHRoZSB4LWF4aXMuIFNldHRpbmcgeSA9ID0gVkFSSUFCTEVfTkFNRSB0ZWxscyBnZ3Bsb3QoKSB3aGF0IHZhcmlhYmxlIHRvIHBsb3Qgb24gdGhlIHktYXhpcy4gRmluYWxseSwgZm9sbG93aW5nIGEgcGx1cyAoKykgc2lnbiwgeW91IHRlbGwgZ2dwbG90IHdoaWNoIHR5cGUgb2YgcGxvdCB0byBjcmVhdGUuIFRoZSBbZ2dwbG90IGNoZWF0c2hlZXRdKGh0dHBzOi8vcnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTUvMDMvZ2dwbG90Mi1jaGVhdHNoZWV0LnBkZikgbGlzdHMgYSBudW1iZXIgb2YgcGxvdHMgdGhhdCB5b3UgY2FuIGNyZWF0ZSB3aXRoIGdncGxvdCwgYXMgd2VsbCBhcyBhIG51bWJlciBvZiBkaWZmZXJlbnQgd2F5cyB0byBzdHlsZSB0aGUgcGxvdC4gV2Ugd2lsbCBwcmFjdGljZSBzZXZlcmFsIG9mIHRoZXNlIGJlbG93LiAKCkZvciBldmVyeSBwbG90IHRoYXQgeW91IHByb2R1Y2UsIEkgd2lsbCBleHBlY3QgeW91IHRvIGFkZCBhIHRpdGxlIGFuZCBsYWJlbHMgdG8gdGhlIHggYW5kIHkgYXhpcy4gWW91IGNhbiBkbyB0aGlzIGFzIGZvbGxvd3M6CgpgYGB7ciBldmFsPUZBTFNFfQpkZiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVkFSSUFCTEVfTkFNRSwgeSA9IFZBUklBQkxFX05BTUUpKSArIAogIGdlb21fY29sKCkgKwogIGxhYnModGl0bGUgPSAiRklMTCBUSVRMRSIsIHggPSAiRklMTCBYLUFYSVMgTEFCRUwiLCB5ID0gIkZJTEwgWS1BWElTIExBQkVMKQpgYGAKClRoZXJlIGFyZSBhbHNvIGEgbnVtYmVyIG9mIHVzZWZ1bCB0b29scyBmb3Igc3R5bGluZyB5b3VyIHBsb3RzLiBGb3IgaW5zdGFuY2Ugd2UgY2FuIHNldCB0aGUgdGhlbWUgb2YgdGhlIHBsb3QgdG8gbG9vayBhIGJpdCBtb3JlIHBvbGlzaGVkIGJ5IGFkZGluZyAiKyB0aGVtZV9idygpIiB0byB0aGUgcGxvdC4gCgpgYGB7ciBldmFsPUZBTFNFfQpkZiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVkFSSUFCTEVfTkFNRSwgeSA9IFZBUklBQkxFX05BTUUpKSArIAogIGdlb21fY29sKCkgKwogIGxhYnModGl0bGUgPSAiRklMTCBUSVRMRSIsIHggPSAiRklMTCBYLUFYSVMgTEFCRUwiLCB5ID0gIkZJTEwgWS1BWElTIExBQkVMIikgKwogIHRoZW1lX2J3KCkKYGBgCgpUd28gc3R5bGluZyBpc3N1ZXMgdGhhdCBJJ20gc3VyZSB3aWxsIGNvbWUgdXAgaW4gbW9zdCBvZiB5b3VyIHBsb3RzIGluY2x1ZGU6CiogY2hhbmdpbmcgeCBvciB5IGF4aXMgdGljayBudW1iZXJzIGZyb20gc2NpZW50aWZpYyB0byBjb21tYSBub3RhdGlvbjogKyBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgT1IgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkKKiB0dXJuaW5nIHggYXhpcyB0aWNrIG1hcmtzIDkwIGRlZ3JlZXMgc28gdGhhdCB0aGV5IGRvIG5vdCBvdmVybGFwOiArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSBPUiArIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKQoKYGBge3IgZXZhbD1GQUxTRX0KZGYgJT4lIAogIGdncGxvdChhZXMoeCA9IFZBUklBQkxFX05BTUUsIHkgPSBWQVJJQUJMRV9OQU1FKSkgKyAKICBnZW9tX2NvbCgpICsKICBsYWJzKHRpdGxlID0gIkZJTEwgVElUTEUiLCB4ID0gIkZJTEwgWC1BWElTIExBQkVMIiwgeSA9ICJGSUxMIFktQVhJUyBMQUJFTCIpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgKyAjVHVybiBsYWJlbHMgOTAgZGVncmVlcwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSAjQ2hhbmdlIGxhYmVscyBmcm9tIHNjaWVudGlmaWMgdG8gY29tbWEgbm90YXRpb24KYGBgCgpTbyBob3cgZG8gd2UgdmlzdWFsaXplIHZhcmlhdGlvbiB3aXRoIGdncGxvdD8gQmVsb3cgSSBkZXNjcmliZSB0d28gZGlmZmVyZW50IHBsb3RzIHRoYXQgeW91IGNhbiBsZXZlcmFnZSB0byB2aXN1YWxpemUgdmFyaWF0aW9uIC0gYSBiYXIgcGxvdCBhbmQgYSBmcmVxdWVuY3kgcGxvdC4gCgojIyMgQmFyIFBsb3QKCkEgKmJhciBwbG90KiBkaXNwbGF5cyB0aGUgbnVtYmVyIG9mIHRpbWVzIGVhY2ggdmFsdWUgYXBwZWFycyBpbiBhIGNhdGVnb3JpYWwgdmFyaWFibGUuIFRoaXMgd2lsbCB0ZWxsIHVzIGhvdyB0aGUgb2JzZXJ2YXRpb25zIGluIHRoZSBkYXRhc2V0ICp2YXJ5KiBpbiByZWdhcmRzIHRvIHRoYXQgdmFyaWFibGUuIEluIG90aGVyIHdvcmRzLCB0aGlzIHBsb3Qgd2lsbCBjb21tdW5pY2F0ZSB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiB5b3VyIGRhdGFzZXQgYnkgdGhhdCB2YXJpYWJsZS4gCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI2RmICU+JSBnZ3Bsb3QoYWVzKHggPSBDQVRFR09SSUNBTF9WQVJJQUJMRSkpICsgZ2VvbV9iYXIoKSArIGxhYnModGl0bGUgPSAiVElUTEUiLCB4ID0gIlgtQVhJUyBOQU1FIiwgeSA9ICJZLUFYSVMgTkFNRSIpCgpob3NwaXRhbHMgJT4lIAogIGdncGxvdChhZXMoeCA9IFRZUEUpKSArIAogIGdlb21fYmFyKCkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIEhvc3BpdGFscyBpbiB0aGUgVVMgYnkgVHlwZSIsIHggPSAiVHlwZSIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKyAjQWRkcyBhIHRpdGxlIHRvIHRoZSBwbG90CiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpICNDaGFuZ2VzIHgtYXhpcyB0aWNrIGxhYmVscyA5MCBkZWdyZWVzIApgYGAKClJlbWVtYmVyIHRoYXQgdGhpcyBkYXRhc2V0IGluY2x1ZGVzIGhvc3BpdGFscyB0aGF0IGFyZSBkZXNpZ25hdGVkIGFzIGNsb3NlZC4gRGVwZW5kaW5nIG9uIHRoZSBxdWVzdGlvbiB3ZSBhcmUgdHJ5aW5nIHRvIGFkZHJlc3MsIHdlIG1heSB3aXNoIHRvIHpvb20gaW4gdG8gb25seSB0aGUgb2JzZXJ2YXRpb25zIHNpZ25pZnlpbmcgYSBob3NwaXRhbCB0aGF0IGlzIG9wZW4gYmVmb3JlIGNyZWF0aW5nIHRoaXMgcGxvdC4gCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI2RmICU+JSBnZ3Bsb3QoYWVzKHggPSBDQVRFR09SSUNBTF9WQVJJQUJMRSkpICsgZ2VvbV9iYXIoKSArIGxhYnModGl0bGUgPSAiVElUTEUiLCB4ID0gIlgtQVhJUyBOQU1FIiwgeSA9ICJZLUFYSVMgTkFNRSIpCgpob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBUWVBFKSkgKyAKICBnZW9tX2JhcigpICsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4gYnkgVHlwZSIsIHggPSAiVHlwZSIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKyAjQWRkcyBhIHRpdGxlIHRvIHRoZSBwbG90CiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpICNDaGFuZ2VzIHgtYXhpcyB0aWNrIGxhYmVscyA5MCBkZWdyZWVzIApgYGAKCiMjIyMgVGl0bGluZyBhIEJhciBQbG90CgpOb3RlIGhvdyBJIHRpdGxlZCBteSBmaXJzdCBwbG90IGFib3ZlOiAiTnVtYmVyIG9mIEhvc3BpdGFscyBpbiB0aGUgVVMgYnkgVHlwZSIgUmVtZW1iZXIgbGFzdCB3ZWVrLCB3aGVuIHdlIGlkZW50aWZpZWQgd2hhdCBtYWtlcyBlYWNoIG9ic2VydmF0aW9uIGluIG91ciBkYXRhc2V0IHVuaXF1ZT8gSGVyZSBJIGFtIGNvdW50aW5nIHRoZSBvYnNlcnZhdGlvbnMgYnkgVHlwZSwgYW5kIGluIG9yZGVyIHRvIGtub3cgd2hhdCBJJ20gY291bnRpbmcsIEkgbmVlZCB0byBrbm93IHdoYXQgZWFjaCBvYnNlcnZhdGlvbiByZWZlcnMgdG8uIEEgZ29vZCBmb3JtdWxhIGZvciB0aXRsaW5nIGJhciBwbG90cyBpcyBhcyBmb2xsb3dzOgoKTnVtYmVyIG9mIF9fX19fIGJ5IFt4LWF4aXMgdmFyaWFibGUgbmFtZV0KCkluIG9yZGVyIHRvIGZpbGwgaW4gdGhlIGJsYW5rIGxpbmUgYWJvdmUsIGNvbnNpZGVyIHRoZSBzdGF0ZW1lbnQgd2UgcHJvZHVjZWQgbGFzdCB3ZWVrOiAiSSBoYXZlIG5yb3coZGYpIHVuaXF1ZSBfX19fXyByZXByZXNlbnRlZCBpbiBteSBkYXRhc2V0LiIgVGhhdCBibGFuayBsaW5lIHRvbGQgdXMgd2hhdCBlYWNoIG9ic2VydmF0aW9uIGluIHRoZSBkYXRhc2V0IHJlcHJlc2VudGVkIC0gb3IgaXRzICpvYnNlcnZhdGlvbmFsIHVuaXQqLiBIb3dldmVyIHdlIGZpbGxlZCBpbiB0aGF0IGJsYW5rIGxpbmUgc2hvdWxkIGFsc28gYmUgaG93IHdlIGZpbGwgaW4gdGhlIHRpdGxlIG9mIGEgYmFyIHBsb3QuIAoKVGhlIFt4LWF4aXMgdmFyaWFibGUgbmFtZV0gc2hvdWxkIGJlIHlvdXIgeC1sYWJlbCBhbmQgIkNvdW50IG9mIF9fX19fXyIgKGZpbGxlZCB0aGUgc2FtZSBhcyBhYm92ZSkgc2hvdWxkIGJlIHlvdXIgeS1sYWJlbC4gTm90ZSB0aGF0IGlmIHlvdSBmaWx0ZXIgeW91ciBkYXRhc2V0LCB5b3Ugc2hvdWxkIGFjY291bnQgZm9yIHRoaXMgaW4gdGhlIHRpdGxlOiAiTnVtYmVyIG9mIEhvc3BpdGFscyBpbiB0aGUgVVMgYnkgVHlwZSIKCiMjIyMjIFdoYXQgaWYgSSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbj8KCklmIHRoaXMgaXMgdGhlIGNhc2UsIHRoZW4geW91ciB5LWF4aXMgaXMgbm90IGNvdW50aW5nIGEgc2luZ2xlIHRoaW5nIGxpa2UgdGhlIG51bWJlciBvZiBob3NwaXRhbHMsIGJ1dCBhIGNvbWJpbmF0aW9uIG9mIHRoaW5ncyBsaWtlIHRoZSBudW1iZXIgb2YgcHJvdmluY2UvY291bnRyeSBwYWlycy4gRm9yIGluc3RhbmNlLCBsZXQncyBzYXkgeW91ciBkYXRhIHJlcG9ydHMgdGhlIHBvcHVsYXRpb24gb2YgZWFjaCBjb3VudHJ5IGVhY2ggeWVhciBhcyBpdCBkb2VzIGluIHRoZSB3b3JsZF9oZWFsdGhfZWNvbiBkYXRhc2V0CgpOb3cgbGV0J3Mgc2F5IHRoYXQgeW91IHdhbnRlZCB0byBwbG90IHRoZSBudW1iZXIgb2YgY291bnRyaWVzIHBlciBjb250aW5lbnQuIElmIHlvdSB3ZXJlIHRvIGNhbGw6CmBgYHtyfQp3b3JsZF9oZWFsdGhfZWNvbiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY29udGluZW50KSkgKyAKICBnZW9tX2JhcigpICsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBDb3VudHJpZXMgcGVyIENvbnRpbmVudCIsIHggPSAiQ29udGluZW50IiwgeSA9ICJDb3VudCBvZiBDb3VudHJpZXMiKSArICNBZGRzIGEgdGl0bGUgdG8gdGhlIHBsb3QKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgI0NoYW5nZXMgeC1heGlzIHRpY2sgbGFiZWxzIDkwIGRlZ3JlZXMgCmBgYAoKLi4uIHlvdSB3b3VsZCBiZSBjb3VudGluZyB0aGUgY29tYmluYXRpb24gb2YgdGhlIG51bWJlciBvZiBjb3VudHJpZXMgYW5kIHllYXJzIHBlciBjb250aW5lbnQuIEVhY2ggY291bnRyeSB3b3VsZCBiZSByZXByZXNlbnRlZCBpbiB0aGUgYmFyIGZvciBldmVyeSB5ZWFyIHRoYXQgaXQgd2FzIGluY2x1ZGVkIGluIHRoZSBkYXRhc2V0LiBJbiBvdGhlciB3b3JkcywgdGhlIHktYXhpcyB3b3VsZCBub3QganVzdCByZXByZXNlbnQgY291bnRyaWVzIGJ1dCBib3RoIGNvdW50cmllcyBhbmQgeWVhcnMuIElmIHdlIHdhbnQgdGhlIHktYXhpcyB0byBvbmx5IGJlIGNvdW50aW5nIG9uZSB0aGluZywgdGhlbiB3ZSBuZWVkIHRvIGZpcnN0IHJlZHVjZSB0aGUgZGF0YXNldCB0byB0aGUgZGlzdGluY3QgdmFsdWVzIG9mIHdoYXQgeW91IHdpc2ggdG8gY291bnQgYW5kIHdoYXQgeW91IHdpc2ggdG8gY291bnQgYnkuIFlvdSBjYW4gZG8gdGhpcyBieSBwbGFjaW5nIHRoZSBkaXN0aW5jdCBjYWxsIGJlZm9yZSBjYWxsaW5nIGdncGxvdCwgb3IgYnkgZmlsdGVyaW5nIHRoZSBkYXRhIHRvIHRoZSBtb3N0IHJlY2VudCB5ZWFyLiAKCmBgYHtyfQp3b3JsZF9oZWFsdGhfZWNvbiAlPiUgCiAgZGlzdGluY3QoY291bnRyeSwgY29udGluZW50KSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBjb250aW5lbnQpKSArIAogIGdlb21fYmFyKCkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIENvdW50cmllcyBwZXIgQ29udGluZW50IiwgeCA9ICJDb250aW5lbnQiLCB5ID0gIkNvdW50IG9mIENvdW50cmllcyIpICsgI0FkZHMgYSB0aXRsZSB0byB0aGUgcGxvdAogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0PTEpKSAjQ2hhbmdlcyB4LWF4aXMgdGljayBsYWJlbHMgOTAgZGVncmVlcwpgYGAKCiMjIyMgU2VsZWN0IGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgZm9yIHdoaWNoIHlvdSB3YW50IHRvIHZpc3VhbGl6ZSB0aGUgZnJlcXVlbmN5IG9mIHRpbWVzIGl0IGFwcGVhcnMgaW4gdGhlIGRhdGFzZXQuIApJIHJlY29tbWVuZCB0aGF0IHlvdSBzZWxlY3Qgb25lIG9mIHRoZSBzYW1lIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB0aGF0IHlvdSBhbmFseXplZCB3aXRoIHRoZSBkaXN0aW5jdCgpIGZ1bmN0aW9uIGxhc3Qgd2Vlay4gQXQgdGhpcyBwb2ludCBob2xkIG9mZiBvbiBzZWxlY3RpbmcgYSBnZW9ncmFwaGljIGNhdGVnb3JpY2FsIHZhcmlhYmxlLCBzdWNoIGFzIENvdW50cnksIFN0YXRlLCBvciBDb3VudHkuIElmIHlvdSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbiwgYmUgc3VyZSB0byByZWR1Y2UgeW91ciBkYXRhc2V0IHRvIHRoZSBkaXN0aW5jdCB2YWx1ZXMgeW91IHdpc2ggdG8gY291bnQuCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI1VuY29tbWVudCB0aGUgbGluZSBiZWxvdyBhbmQgZmlsbCBhcHByb3ByaWF0ZWx5LiBBZGQgYSB0aXRsZSBhbmQgbGFiZWxzIHRvIHlvdXIgcGxvdHMsIGFuZCBhZGp1c3QgaXRzIHN0eWxlIHRvIGJlIGxlZ2libGUuCiNfX19fXyAlPiUgZ2dwbG90KGFlcyh4ID0gX19fX18pKSArIGdlb21fYmFyKCkKCiNJZiBxdWFsaWZpZWQ6CiNfX19fXyAlPiUgZGlzdGluY3QoX19fX18pICU+JSBnZ3Bsb3QoYWVzKHggPSBfX19fXykpICsgZ2VvbV9iYXIoKQpgYGAKClJlZmxlY3Qgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiBjYXRlZ29yaWVzIGluIHRoZSBkYXRhc2V0LiBJcyB0aGVyZSBhbiBldmVuIGRpc3RyaWJ1dGlvbiBvZiBvYnNlcnZhdGlvbnMgYWNyb3NzIGVhY2ggY2F0ZWdvcnksIG9yIGFyZSBjZXJ0YWluIGNhdGVnb3JpZXMgbW9yZSByZXByZXNlbnRlZCB0aGFuIG90aGVycz8gV2h5IG1pZ2h0IHRoaXMgYmU/IFdoYXQgZG9lcyB0aGlzIHNheSBhYm91dCB0aGUgc29jaWFsLCBwb2xpdGljYWwsIG9yIGVjb25vbWljIGxhbmRzY2FwZSBvZiB5b3VyIHRvcGljPyAKCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgcmVzcG9uc2UgaGVyZS4gCmBgYAoKUmVmbGVjdCBvbiB3aGF0IHlvdSBsZWFybmVkIGFib3V0IHRoZSBoaXN0b3J5IG9mIHRoZSBjYXRlZ29yaWVzIHlvdSBwbG90dGVkIGFib3ZlIGluIGxhc3Qgd2VlaydzIGxhYi4gSG93IGhhdmUgdGhlIHNvY2lhbCwgcG9saXRpY2FsLCBhbmQgZWNvbm9taWMgZm9yY2VzIHNoYXBpbmcgdGhpcyBjYXRlZ29yaXphdGlvbiBpbXBhY3RlZCBob3cgd2UgY291bnQgb2JzZXJ2YXRpb25zIHJlbGF0ZWQgdG8gdGhpcyB0b3BpYz8gSG93IG1pZ2h0IHRoaXMgcGxvdCBsb29rIGRpZmZlcmVudCBpZiB0aGlzIHZhcmlhYmxlIGhhZCBiZWVuIGNhdGVnb3JpemVkIGluIGEgZGlmZmVyZW50IHdheT8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgcmVzcG9uc2UgaGVyZS4gCmBgYAoKIyMjIEZyZXF1ZW5jeSBQbG90CgpBICpmcmVxdWVuY3kgcGxvdCogd2lsbCBkaXNwbGF5IHRoZSBkaXN0cmlidXRpb24gb2YgdmFsdWVzIGluIGEgbnVtZXJpYyB2YXJpYWJsZSB3aXRoaW4gYSBkZXNpZ25hdGVkIHNldCBvZiBpbmNyZW1lbnRzLiBUaGlzIHdpbGwgdGVsbCB1cyBob3cgdGhlIG9ic2VydmF0aW9ucyBpbiB0aGUgZGF0YXNldCAqdmFyeSogaW4gcmVnYXJkcyB0byB0aGF0IHZhcmlhYmxlLiBJbiBvdGhlciB3b3JkcywgdGhpcyBwbG90IHdpbGwgY29tbXVuaWNhdGUgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4geW91ciBkYXRhc2V0IGJyb2tlbiBkb3duIGludG8gaW5jcmVtZW50cyBvZiB0aGF0IHZhcmlhYmxlLiAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojZGYgJT4lIGdncGxvdChhZXMoeCA9IE5VTUVSSUNfVkFSSUFCTEUpKSArIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxKSArIGxhYnModGl0bGUgPSAiVElUTEUiLCB4ID0gIlgtQVhJUyBOQU1FIiwgeSA9ICJZLUFYSVMgTkFNRSIpCgpob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBCRURTKSkgKwogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxMCkgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEJlZHMgYWNyb3NzIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiIsIHggPSAiQmVkcyIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKwogIHRoZW1lX2J3KCkKYGBgCgo+IE5vdGUgdGhhdCBiaW53aWR0aCByZWZlcnMgdG8gdGhlIHNpemUgb2YgdGhlIGluY3JlbWVudHMgYXQgd2hpY2ggZnJlcXVlbmN5IHdpbGwgYmUgY2FsY3VsYXRlZC4gQWJvdmUgdGhlIGJpbndpZHRoIGlzIHNldCB0byAxMC4gVGhpcyBtZWFucyB0aGF0IGdncGxvdCB3aWxsIGRpc3BsYXkgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIHZhbHVlIGF0IGludGVydmFscyBvZiAxMCwgMjAsIDMwLCA0MCwgZXRjLiBXaGVuIHdlIHNldCB0aGUgYmluZHdpZHRoIHRvIDEsIGdncGxvdCB3aWxsIGRpc3BsYXkgdGhlIGZyZXF1ZW5jeSBvZiBlYWNoIHZhbHVlIGF0IGludGVydmFscyBvZiAxLCAyLCAzLCA0LiBldGMuIFdoYXQgZGlmZmVyZW5jZSBkb2VzIHRoaXMgbWFrZT8gCgpOb3RpY2Ugd2hhdCBoYXBwZW5zIHdoZW4gd2Ugc2V0IHRoZSBiaW53aWR0aCB0byAxLiBXaGlsZSBhYm92ZSB3ZSBjb3VudCB0aGUgbnVtYmVyIG9mIGhvc3BpdGFscyB3aXRoIDAtMTAgYmVkcyAgMTAtMjAgYmVkcywgMjAtMzAgYmVkcywgZXRjLCB0aGlzIHdpbGwgY291bnQgdGhlIG51bWJlciBvZiBob3NwaXRhbHMgd2l0aCAwLTEgYmVkcywgMS0yIGJlZHMsIDItMyBiZWRzLCBhbmQgc28gb24uIEJlY2F1c2Ugd2UgYXJlIGNvdW50aW5nIHRoZSBudW1iZXIgaW4gc3VjaCBzbWFsbCBpbmNyZW1lbnRzLCB0aGUgcGxvdCB3aWxsIGxvb2sgbXVjaCBtb3JlIGphZ2dlZCBhbmQgd2lsbCB0YWtlIGEgbG9uZ2VyIHRpbWUgdG8gbG9hZC4gVGhpcyBwbG90IGRpc3BsYXlzIHRoZSBjb3VudHMgaW4gKmZpbmVyKiBncmFudWxhcml0eSB0aGFuIHRoZSBmaXJzdCBwbG90LiAKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9Cmhvc3BpdGFscyAlPiUgCiAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIpICU+JQogIGdncGxvdChhZXMoeCA9IEJFRFMpKSArCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEpICsKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBCZWRzIGFjcm9zcyBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4iLCB4ID0gIkJlZHMiLCB5ID0gIkNvdW50IG9mIEhvc3BpdGFscyIpICsKICB0aGVtZV9idygpCmBgYAoKV2hlbiB3ZSBzZXQgdGhlIGJpbndpZHRoIHRvIDEwMCwgd2UgY291bnQgdGhlIG51bWJlciBvZiBob3NwaXRhbHMgd2l0aCAwLTEwMCBiZWRzLCAxMDAtMjAwIGJlZHMsIDIwMC0zMDAgYmVkcywgYW5kIHNvIG9uLiBCZWNhdXNlIHdlIGFyZSBjb3VudGluZyB0aGUgbnVtYmVyIGluIGxhcmdlciBpbmNyZW1lbnRzLCB0aGUgcGxvdCB3aWxsIGxvb2sgbXVjaCBzbW9vdGhlciBhbmQgd2lsbCB0YWtlIGxlc3MgdGltZSB0byBsb2FkLiBUaGlzIHBsb3QgZGlzcGxheXMgdGhlIGNvdW50cyBpbiAqdGhpY2tlciogZ3JhbnVsYXJpdHkgdGhhbiB0aGUgZmlyc3QgcGxvdC4KYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9Cmhvc3BpdGFscyAlPiUgCiAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIpICU+JQogIGdncGxvdChhZXMoeCA9IEJFRFMpKSArCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEwMCkgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEJlZHMgYWNyb3NzIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiIsIHggPSAiQmVkcyIsIHkgPSAiQ291bnQgb2YgSG9zcGl0YWxzIikgKwogIHRoZW1lX2J3KCkKYGBgCgojIyMjIFRpdGxpbmcgYSBGcmVxdWVuY3kgUGxvdAoKTm90ZSBob3cgSSB0aXRsZWQgbXkgcGxvdCBhYm92ZTogIkRpc3RyaWJ1dGlvbiBvZiBCZWRzIGFjcm9zcyBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4iIENvbnNpZGVyIGFnYWluIHdoYXQgbWFrZXMgZWFjaCBvYnNlcnZhdGlvbiB1bmlxdWUuIEEgZ29vZCBmb3JtdWxhIGZvciB0aXRsaW5nIGZyZXF1ZW5jeSBwbG90cyBpcyBhcyBmb2xsb3dzOgoKRnJlcXVlbmN5IG9mIFt4LWF4aXMgdmFyaWFibGUgbmFtZV0gYWNyb3NzIF9fX19fIAoKQWdhaW4sIHdlIGNhbiBmaWxsIGluIHRoZSBibGFuayB3aXRoIG91ciBvYnNlcnZhdGlvbmFsIHVuaXQuIFRoZSBbeC1heGlzIHZhcmlhYmxlIG5hbWVdIHNob3VsZCBiZSB5b3VyIHgtbGFiZWwgYW5kICJDb3VudCBvZiBfX19fX18iIChmaWxsZWQgdGhlIHNhbWUgYXMgYWJvdmUpIHNob3VsZCBiZSB5b3VyIHktbGFiZWwuCgojIyMjIFdoYXQgaWYgSSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbj8KCkxldCdzIHRhbGsgYWJvdXQgd2hhdCB3b3VsZCBoYXBwZW4gaWYgSSB3ZXJlIHRvIG1ha2UgYSBmcmVxdWVuY3kgcGxvdCBvZiB0aGUgVG90YWwuQ2FzZXMgaW4gdGhlIGNhc2VzIGRhdGFzZXQ6CmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQpjYXNlcyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gVG90YWwuQ2FzZXMpKSArIAogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxMDAwMCkgKwogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIENhc2VzIGFjcm9zcyBfX19fIiwgeCA9ICJUb3RhbCBDYXNlcyIsIHkgPSAiQ291bnQgb2YgX19fX18iKSArICMgVG8gYWRkIHRpdGxlcyBhbmQgbGFiZWxzCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpICsgI1R1cm4gbGFiZWxzIDkwIGRlZ3JlZXMKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgI0NoYW5nZSBsYWJlbHMgZnJvbSBzY2llbnRpZmljIHRvIGNvbW1hIG5vdGF0aW9uCmBgYAoKV2Uga25vdyB0aGF0IGVhY2ggb2JzZXJ2YXRpb24gaW4gdGhlIGNhc2VzIGRhdGFzZXQgcmVmZXJzIHRvIGEgcHJvdmluY2UvY291bnRyeSBwYWlyLiBTbyBoZXJlIEknbSBjb3VudGluZyB0aGUgbnVtYmVyIG9mIHByb3ZpbmNlL2NvdW50cmllcyBpbiBlYWNoIGJyYWNrZXQgb2YgdG90YWwgY2FzZXMuIFNpbmNlIG9ubHkgc29tZSBjb3VudHJpZXMgaW4gdGhpcyBkYXRhc2V0IGFyZSBicm9rZW4gaW50byBwcm92aW5jZXMsIHdlIGFyZSBjb21wYXJpbmcgY291bnRzIG9mIGNhc2VzIGFjcm9zcyBkaWZmZXJlbnQgZ2VvZ3JhcGhpYyBzY2FsZXMgLSBzb21ldGltZXMgYXQgdGhlIHByb3ZpbmNlIGxldmVsIGFuZCBzb21ldGltZXMgYXQgdGhlIGNvdW50cnkgbGV2ZWwuIEluIHRoaXMgY2FzZSwgaXQgbWFrZXMgbW9yZSBzZW5zZSB0byB0b3RhbCB1cCB0aGUgbnVtYmVyIG9mIGNhc2VzIHBlciBjb3VudHJ5IGFuZCB0aGVuIHBsb3QgdGhlIGRpc3RyaWJ1dGlvbiBvZiBjYXNlcyBhY3Jvc3MgY291bnRyaWVzLiBXZSBjYW4gdXNlIGdyb3VwX2J5KCkgYW5kIHN1bW1hcml6ZSgpIHRvIGRvIHRoaXM6CgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KY2FzZXMgJT4lIAogIGdyb3VwX2J5KENvdW50cnkuUmVnaW9uKSAlPiUKICBzdW1tYXJpemUoVG90YWwuQ2FzZXMgPSBzdW0oVG90YWwuQ2FzZXMsIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBUb3RhbC5DYXNlcykpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEwMDAwKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQ2FzZXMgYWNyb3NzIENvdW50cmllcyIsIHggPSAiVG90YWwgQ2FzZXMiLCB5ID0gIkNvdW50IG9mIENvdW50cmllcyIpICsgIyBUbyBhZGQgdGl0bGVzIGFuZCBsYWJlbHMKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdD0xKSkgKyAjVHVybiBsYWJlbHMgOTAgZGVncmVlcwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSAjQ2hhbmdlIGxhYmVscyBmcm9tIHNjaWVudGlmaWMgdG8gY29tbWEgbm90YXRpb24KYGBgCgpXaGF0IGFib3V0IHRoZSB3b3JsZF9oZWFsdGhfZWNvbiBkYXRhPyBXaXRob3V0IHNlcGFyYXRpbmcgb3V0IHRoZXNlIHVuaXRzIG9mIG9ic2VydmF0aW9uLCB3ZSB3b3VsZCBiZSB2aXN1YWxpemluZyBtdWx0aXBsZSB2YWx1ZXMgcmVwb3J0ZWQgYXQgdGhlIHNhbWUgcGxhY2UgYXQgZGlmZmVyZW50IHBlcmlvZHMgaW4gdGltZSAoaS5lLiBldmVyeSB5ZWFyIHNpbmNlIDE5OTUpLiBJbnN0ZWFkLCB3ZSB3YW50IHRvIHpvb20gaW50byBhIHNpbmdsZSB5ZWFyIGluIHRoZSBkYXRhc2V0IHNvIHdlIGFyZSBqdXN0IGNvbXBhcmluZyB2YWx1ZXMgYWNyb3NzIHBsYWNlLiAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQp3b3JsZF9oZWFsdGhfZWNvbiAlPiUgCiAgZmlsdGVyKHllYXIgPT0gbWF4KHllYXIsIG5hLnJtID0gVFJVRSkpICU+JQogIGdncGxvdChhZXMoeCA9IHRvdF9oZWFsdGhfc3BfcHApKSArIAogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAxMDApICsKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBUb3RhbCBIZWFsdGggU3BlbmRpbmcgcGVyIFBlcnNvbiBhY3Jvc3MgQ291bnRyaWVzIGluIDIwMTAiLCB4ID0gIlRvdGFsIEhlYWx0aCBTcGVuZGluZyBwZXIgUGVyc29uIiwgeSA9ICJDb3VudCBvZiBDb3VudHJpZXMiKSArICMgVG8gYWRkIHRpdGxlcyBhbmQgbGFiZWxzCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3Q9MSkpICsgI1R1cm4gbGFiZWxzIDkwIGRlZ3JlZXMKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgI0NoYW5nZSBsYWJlbHMgZnJvbSBzY2llbnRpZmljIHRvIGNvbW1hIG5vdGF0aW9uCmBgYAo+IE5vdGUgdGhlIGFkZGl0aW9uIHRvIG15IHRpdGxlIGFib3ZlLiBJZiB5b3UgZmlsdGVyIHlvdXIgZGF0YXNldCwgdGhlIGZvcm11bGEgZm9yIHRpdGxpbmcgY2hhbmdlcyBhIGJpdCB0byBGcmVxdWVuY3kgb2YgW3gtYXhpcyB2YXJpYWJsZSBuYW1lXSBhY3Jvc3MgX19fX18gaW4gW2ZpbHRlcmVkIHZhbHVlXQoKIyMjIyBTZWxlY3QgYSBudW1lcmljIHZhcmlhYmxlIGZvciB3aGljaCB5b3Ugd2FudCB0byB2aXN1YWxpemUgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIHNldCBvZiB2YWx1ZXMuIAoKQmUgc3VyZSB0byBzZWxlY3QgYSB2YXJpYWJsZSB0aGF0IGRlc2NyaWJlcyBzb21ldGhpbmcgYWJvdXQgdGhlIG9ic2VydmF0aW9uYWwgdW5pdCBhbmQgbm90IGFub3RoZXIgY2F0ZWdvcmljYWwgdmFyaWFibGUgaW4geW91ciBkYXRhc2V0LiBGb3IgaW5zdGFuY2UsIGxldCdzIHNheSB5b3UgaGFkIHRoZSBmb2xsb3dpbmcgZGF0YSB0YWJsZSAtIHdpdGggZWFjaCByb3cgcmVwb3J0aW5nIGFuIGVudmlyb25tZW50YWwgdmlvbGF0aW9uIGF0IGEgZmFjaWxpdHk6CgpWaW9sYXRpb24gTnVtYmVyIHwgRmFjaWxpdHkgTmFtZSB8IEZhY2lsaXR5IFRvd24gfCBQb3B1bGF0aW9uIG9mIEZhY2lsaXR5IFRvd24KX19fX19fX19fX19fX19fX18gfCBfX19fX19fX19fX19fX19fXyB8IF9fX19fX19fX19fX19fX19fIHwgX19fX19fX19fX19fX19fX18gCjEyMzQ1NjcgfCBGYWNpbGl0eSBBIHwgVGFycnl0b3duIHwgOTAwMDAKMjM0NTY3OCB8IEZhY2lsaXR5IEIgfCBUYXJyeXRvd24gfCA5MDAwMAozNDU2Nzg5IHwgRmFjaWxpdHkgQyB8IEFub3RoZXIgVG93biB8IDcwMDAwCgpJbiB0aGlzIHRhYmxlLCB3ZSB3b3VsZCBub3Qgd2FudCB0byBjcmVhdGUgYSBmcmVxdWVuY3kgcGxvdCB3aXRoIHBvcHVsYXRpb24gb2YgZmFjaWxpdHkgdG93bi4gVGhpcyBpcyBiZWNhdXNlIG91ciBvYnNlcnZhdGlvbmFsIHVuaXQgaXMgYSB2aW9sYXRpb24sIG5vdCBhIHRvd24sIGFuZCBwb3B1bGF0aW9uIGRvZXMgbm90IGRlc2NyaWJlIHNvbWV0aGluZyBhYm91dCB0aGUgdmlvbGF0aW9uIGJ1dCBpbnN0ZWFkIGRlc2NyaWJlcyBzb21ldGhpbmcgYWJvdXQgdGhlIHRvd24gdGhlIGZhY2lsaXR5IGlzIGluLiBJZiB3ZSB3ZXJlIHRvIGNyZWF0ZSBhIGZyZXF1ZW5jeSBwbG90IHdpdGggdGhpcyB2YXJpYWJsZSwgd2Ugd291bGQgYmUgY291bnRpbmcgdGhlIG51bWJlciBvZiB0aW1lcyBlYWNoIHBvcHVsYXRpb24gdmFsdWUgYXBwZWFycyBpbiB0aGUgZGF0YXNldCAtIHNvbWV0aGluZyB0aGF0IGRvZXMgbm90IG1ha2UgbXVjaCBzZW5zZSwgc2luY2Ugd2UgY2FuIGhhdmUgdGhlIHNhbWUgdG93bidzIHBvcHVsYXRpb24gdG93biBhcHBlYXIgc2V2ZXJhbCB0aW1lcyBpbiB0aGUgZGF0YXNldCBpZiB0aGVyZSBhcmUgbW9yZSB0aGFuIHZpb2xhdGlvbnMgb3IgbW9yZSB0aGFuIG9uZSBmYWNpbGl0aWVzIGluIGEgdG93bi4gCgpJZiB5b3UgaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24sIGJlIHN1cmUgdG8gZmlyc3Qgem9vbSBpbnRvIGEgc2V0IG9mIG9ic2VydmF0aW9ucyBpbiB5b3VyIGRhdGEgKHVzaW5nIGZpbHRlcigpKSBvciB6b29tIG91dCB0byBnZW5lcmFsaXplIHRoZSBvYnNlcnZhdGlvbnMgKGNhbGxpbmcgZ3JvdXBfYnkoKSwgc3VtbWFyaXplKCksIGFuZCB1bmdyb3VwKCkpLiAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojVW5jb21tZW50IHRoZSBsaW5lIGJlbG93IGFuZCBmaWxsIGFwcHJvcHJpYXRlbHkuIEFkZCBhIHRpdGxlIGFuZCBsYWJlbHMgdG8geW91ciBwbG90cy4KI19fX19fICU+JSBnZ3Bsb3QoYWVzKHggPSBfX19fXykpICsgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IF9fX19fKSAKYGBgCgpUaGlzIGdpdmVzIHVzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBkaXN0cmlidXRpb24gb2YgdmFsdWVzIGluIHRoZSBkYXRhc2V0LiBSZWZsZWN0IG9uIHRoZSBkaXN0cmlidXRpb24gb2YgdmFsdWVzLiBXaGF0IGFyZSB0aGUgcmFuZ2Ugb2YgdmFsdWVzIHJlcHJlc2VudGVkIGluIHRoZSBkYXRhPyBBcmUgdGhlIHZhbHVlcyBldmVubHkgZGlzdHJpYnV0ZWQsIG9yIGFyZSBjZXJ0YWluIHZhbHVlcyBtb3JlIHJlcHJlc2VudGVkIHRoYW4gb3RoZXJzPyBXaHkgbWlnaHQgdGhpcyBiZT8gRG8gYW55IG9mIHRoZSB2YWx1ZXMgc3VycHJpc2UgeW91PyBXaHk/IAoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCByZXNwb25zZSBoZXJlLiAKYGBgCgpXaHkgZGlkIHlvdSBzZWxlY3QgdGhlIGJpbndpZHRoIHRoYXQgeW91IGRpZD8gSG93IG1pZ2h0IHRoZSBzdG9yeSB5b3VyIHBsb3QgdGVsbHMgY2hhbmdlIGlmIHlvdSB3ZXJlIHRvIGNoYW5nZSB0aGUgYmlud2lkdGg/IFdoYXQgYW5vbWFsaWVzIG1pZ2h0IGJlIGhpZGRlbiB3aXRoIGEgbGFyZ2VyIGJpbndpZHRoLCBhbmQgd2hhdCB0cmVuZHMgbWlnaHQgYmUgaGlkZGVuIHdpdGggYSBzbWFsbGVyIGJpbndpZHRoPwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCByZXNwb25zZSBoZXJlLiAKYGBgCgpDaGVjayBob3cgdGhlIG51bWVyaWMgdmFyaWFibGUgd2FzIGRlZmluZWQgaW4gdGhlIGRhdGEgZGljdGlvbmFyeSwgYW5kIHF1b3RlIHRoZSBkZWZpbnRpb24gYmVsb3cuIEhvdyBtaWdodCB0aGUgY291bnRzIHJlcHJlc2VudGVkIGluIHlvdXIgZnJlcXVlbmN5IHBsb3QgYXBwZWFyIGRpZmZlcmVudGx5IGlmIHRoaXMgdmFyaWFibGUgd2FzIGRlZmluZWQgZGlmZmVyZW50bHk/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHJlc3BvbnNlIGhlcmUuIApgYGAKCiMjIyBQcm9kdWNlIHR3byBtb3JlIHBsb3RzIHRoYXQgZGlzcGxheSB2YXJpYXRpb24uIENvbnRpbnVlIHRvIGhvbGQgb2ZmIG9uIHNlbGVjdGluZyBhIGdlb2dyYXBoaWMgY2F0ZWdvcmljYWwgdmFyaWFibGUuIAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNGaWxsIHRoZSBjb2RlIGZvciBwbG90IDEgaGVyZS4gQWRkIGEgdGl0bGUgYW5kIGxhYmVscyB0byB5b3VyIHBsb3RzLgpgYGAKCldoYXQgcXVlc3Rpb24gbWlnaHQgdGhpcyBhbmFseXNpcyBoZWxwIHRvIGFkZHJlc3M/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKQXJlIHRoZXJlIGFueSBvdGhlciB2YXJpYWJsZXMgaW4geW91ciBkYXRhc2V0IHRoYXQgeW91IG5lZWQgdG8gdGFrZSBpbnRvIGNvbnNpZGVyYXRpb24gYmVmb3JlIGRpcmVjdGluZyB0aGlzIGFuYWx5c2lzIHRvd2FyZHMgYW5zd2VyaW5nIHRoYXQgcXVlc3Rpb24/IEluIG90aGVyIHdvcmRzLCBkbyB5b3UgbmVlZCB0byB6b29tIGludG8gYW55IHNwZWNpZmljIGFyZWFzIG9mIHRoZSBkYXRhc2V0IChieSBmaWx0ZXJpbmcpIGluIG9yZGVyIHRvIGFwcHJvcHJpYXRlbHkgYWRkcmVzcyB0aGlzIHF1ZXN0aW9uPyBJZiBzbywgd2hpY2g/IEJlIHN1cmUgdG8gYWRqdXN0IHlvdXIgcGxvdCBhYm92ZSB0byByZWZsZWN0IHRoaXMuCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKV2hhdCBpbnNpZ2h0IGNhbiB5b3UgZHJhdyBmcm9tIHRoaXMgcGxvdD8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI0ZpbGwgdGhlIGNvZGUgZm9yIHBsb3QgMiBoZXJlLiBBZGQgYSB0aXRsZSBhbmQgbGFiZWxzIHRvIHlvdXIgcGxvdHMuCmBgYAoKV2hhdCBxdWVzdGlvbiBtaWdodCB0aGlzIGFuYWx5c2lzIGhlbHAgdG8gYWRkcmVzcz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpBcmUgdGhlcmUgYW55IG90aGVyIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGFzZXQgdGhhdCB5b3UgbmVlZCB0byB0YWtlIGludG8gY29uc2lkZXJhdGlvbiBiZWZvcmUgZGlyZWN0aW5nIHRoaXMgYW5hbHlzaXMgdG93YXJkcyBhbnN3ZXJpbmcgdGhhdCBxdWVzdGlvbj8gSW4gb3RoZXIgd29yZHMsIGRvIHlvdSBuZWVkIHRvIHpvb20gaW50byBhbnkgc3BlY2lmaWMgYXJlYXMgb2YgdGhlIGRhdGFzZXQgKGJ5IGZpbHRlcmluZykgaW4gb3JkZXIgdG8gYXBwcm9wcmlhdGVseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IElmIHNvLCB3aGljaD8gQmUgc3VyZSB0byBhZGp1c3QgeW91ciBwbG90IGFib3ZlIHRvIHJlZmxlY3QgdGhpcy4KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpXaGF0IGluc2lnaHQgY2FuIHlvdSBkcmF3IGZyb20gdGhpcyBwbG90PwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCiMjIENvLXZhcmlhdGlvbgoKQ28tdmFyaWF0aW9uIGlzIHRoZSBleHRlbnQgdG8gd2hpY2ggdGhlIHZhbHVlcyB0aGF0IGNvbnN0aXR1dGUgdHdvIG9yIG1vcmUgdmFyaWFibGVzIHZhcnkgaW4gcmVsYXRpb24gdG8gb25lIGFub3RoZXIuIFRvIHZpc3VhbGl6ZSBjby12YXJpYXRpb24sIHdlIG1pZ2h0IGNyZWF0ZToKCiMjIyBDb3VudCBQbG90cwoKKkNvdW50IHBsb3RzKiBkaXNwbGF5IGhvdyBtYW55IHRpbWVzIHR3byBjYXRlZ29yaWNhbCB2YWx1ZXMgYXBwZWFyIHRvZ2V0aGVyIGluIGEgZGF0YXNldC4gCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI2RmICU+JSBnZ3Bsb3QoYWVzKHggPSBDQVRFR09SSUNBTF9WQVJJQUJMRSwgeSA9IENBVEVHT1JJQ0FMX1ZBUklBQkxFKSkgKyBnZW9tX2NvdW50KCkKCmhvc3BpdGFscyAlPiUgCiAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIpICU+JQogIGdncGxvdChhZXMoeCA9IFRZUEUsIHkgPSBPV05FUikpICsgCiAgZ2VvbV9jb3VudCgpICsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiBieSBUeXBlIGFuZCBPd25lcnNoaXAiLCB4ID0gIlR5cGUiLCB5ID0gIk93bmVyc2hpcCIpICsgIyBUbyBhZGQgdGl0bGVzIGFuZCBsYWJlbHMKICB0aGVtZV9idygpIApgYGAKIyMjIyBUaXRsaW5nIGEgQ291bnQgUGxvdAoKTm90ZSBob3cgSSB0aXRsZWQgbXkgcGxvdCBhYm92ZTogIk51bWJlciBvZiBIb3NwaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4gYnkgVHlwZSBhbmQgT3duZXJzaGlwIiBDb25zaWRlciBhZ2FpbiB3aGF0IG1ha2VzIGVhY2ggb2JzZXJ2YXRpb24gdW5pcXVlLiBIZXJlIEkgYW0gY291bnRpbmcgdGhlIG9ic2VydmF0aW9ucyBieSBUeXBlIGFuZCBPd25lcnNoaXAsIGFuZCBpbiBvcmRlciB0byBrbm93IHdoYXQgSSdtIGNvdW50aW5nLCBJIG5lZWQgdG8ga25vdyB3aGF0IGVhY2ggb2JzZXJ2YXRpb24gcmVmZXJzIHRvLiBBIGdvb2QgZm9ybXVsYSBmb3IgdGl0bGluZyBjb3VudCBwbG90cyBpcyBhcyBmb2xsb3dzOgoKQ291bnQgb2YgX19fX18gYnkgW3gtYXhpcyB2YXJpYWJsZSBuYW1lXSBhbmQgW3ktYXhpcyB2YXJpYWJsZSBuYW1lXQoKVGhlIGJsYW5rIHNob3VsZCBiZSBmaWxsZWQgd2l0aCB5b3VyIHVuaXQgb2Ygb2JzZXJ2YXRpb24uIFRoZSBbeC1heGlzIHZhcmlhYmxlIG5hbWVdIHNob3VsZCBiZSB5b3VyIHgtbGFiZWwgYW5kICJDb3VudCBvZiBfX19fX18iIChmaWxsZWQgdGhlIHNhbWUgYXMgYWJvdmUpIHNob3VsZCBiZSB5b3VyIHktbGFiZWwuCgojIyMjIFdoYXQgaWYgSSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbj8KCklmIHRoaXMgaXMgdGhlIGNhc2UgSSB3b3VsZCBlbmNvdXJhZ2UgeW91IHRvIGluY2x1ZGUgb25lIG9mIHRoZSBxdWFsaWZpZWQgdmFyaWFibGVzIGluIHRoZSB4IG9yIHktYXhpcy4gRm9yIGluc3RhbmNlIGlmIHdvcmxkX2hlYWx0aF9lY29uIGlzIHF1YWxpZmllZCBieSBjb3VudHJ5IGFuZCB5ZWFyLCBJIGNhbiBpbmNsdWRlIHllYXIgYXMgdGhlIHktYXhpcyBiZWxvdyB0byB2aXN1YWxpemUgaG93IGNvdW50cyBvZiBvYnNlcnZhdGlvbnMgY2hhbmdlIG92ZXIgdGltZS4gKE5vdGljZSBob3cgdGhleSBkb24ndCBpbiB0aGUgcGxvdCBiZWxvdy4gKQoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CndvcmxkX2hlYWx0aF9lY29uICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjb250aW5lbnQsIHkgPSBhcy5mYWN0b3IoeWVhcikpKSArIAogIGdlb21fY291bnQoKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3Q9MSkpICsKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBUb3RhbCBIZWFsdGggU3BlbmRpbmcgcGVyIFBlcnNvbiBhY3Jvc3MgQ291bnRyaWVzIiwgeCA9ICJDb250aW5lbnQiLCB5ID0gIlllYXIiKSArICMgVG8gYWRkIHRpdGxlcyBhbmQgbGFiZWxzCiAgdGhlbWVfYncoKSAKYGBgCgojIyMgU3RhY2tlZCBGcmVxdWVuY3kgUGxvdHMgCgoqU3RhY2tlZCBmcmVxdWVuY3kgcGxvdHMqIGRpc3BsYXkgdGhlIGRpc3RyaWJ1dGlvbiBvZiBudW1lcmljIHZhbHVlcyBpbiBhIHZhcmlhYmxlLCBncm91cGVkIGJ5IGEgY2F0ZWdvcmljYWwgdmFsdWUuCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI2RmICU+JSBnZ3Bsb3QoYWVzKHggPSBOVU1FUklDX1ZBUklBQkxFLCBjb2wgPSBDQVRFR09SSUNBTF9WQVJJQUJMRSkpICsgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEpCgpob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBCRURTLCBjb2wgPSBUWVBFKSkgKyAKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMTAwKSArCiAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgb2YgQmVkcyBhY3Jvc3MgSG9zcGl0YWxzIGluIHRoZSBVUyB0aGF0IGFyZSBPcGVuIGJ5IEhvc3BpdGFsIFR5cGUiLCB4ID0gIkJlZHMiLCB5ID0gIkNvdW50IG9mIEhvc3BpdGFsIiwgY29sID0gIlR5cGUiKSArICMgVG8gYWRkIHRpdGxlcyBhbmQgbGFiZWxzCiAgdGhlbWVfYncoKSAKYGBgCgojIyMjIFRpdGxpbmcgYSBTdGFja2VkIEZyZXF1ZW5jeSBQbG90CgpOb3RlIGhvdyBJIHRpdGxlZCBteSBwbG90IGFib3ZlOiAiRnJlcXVlbmN5IG9mIEJlZHMgYWNyb3NzIEhvc3BpdGFscyBpbiB0aGUgVVMgdGhhdCBhcmUgT3BlbiBieSBIb3NwaXRhbCBUeXBlIiBDb25zaWRlciBhZ2FpbiB3aGF0IG1ha2VzIGVhY2ggb2JzZXJ2YXRpb24gdW5pcXVlLiBIZXJlIEkgYW0gY291bnRpbmcgdGhlIG9ic2VydmF0aW9ucyBieSBudW1iZXIgb2YgQmVkcyBhbmQgSG9zcGl0YWwgVHlwZS4gQSBnb29kIGZvcm11bGEgZm9yIHRpdGxpbmcgc3RhY2tlZCBmcmVxdWVuY3kgcGxvdHMgaXMgYXMgZm9sbG93czogCgpGcmVxdWVuY3kgb2YgW3gtYXhpcyB2YXJpYWJsZSBuYW1lXSBhY3Jvc3MgX19fX18gYnkgW2NvbCB2YXJpYWJsZSBuYW1lXQoKVGhlIGJsYW5rIHNob3VsZCBiZSBmaWxsZWQgd2l0aCB5b3VyIHVuaXQgb2Ygb2JzZXJ2YXRpb24uIFRoZSBbeC1heGlzIHZhcmlhYmxlIG5hbWVdIHNob3VsZCBiZSB5b3VyIHgtbGFiZWwsICJDb3VudCBvZiBfX19fX18iIChmaWxsZWQgdGhlIHNhbWUgYXMgYWJvdmUpIHNob3VsZCBiZSB5b3VyIHktbGFiZWwsIGFuZCB0aGUgW2NvbCB2YXJpYWJsZSBuYW1lXSBzaG91bGQgYmUgeW91ciBjb2wtbGFiZWwuCgojIyMjIFdoYXQgaWYgSSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbj8KCklmIHRoaXMgaXMgdGhlIGNhc2UgSSB3b3VsZCBlbmNvdXJhZ2UgeW91IHRvIGluY2x1ZGUgb25lIG9mIHRoZSBxdWFsaWZpZWQgdmFyaWFibGVzIGluIHRoZSBjb2wgdmFyaWFibGUuIEZvciBpbnN0YW5jZSwgaWYgd29ybGRfaGVhbHRoX2Vjb24gaXMgcXVhbGlmaWVkIGJ5IGNvdW50cnkgYW5kIHllYXIsIEkgY2FuIGluY2x1ZGUgeWVhciBhcyB0aGUgY29sIHZhcmlhYmxlIGJlbG93IHRvIHZpc3VhbGl6ZSBob3cgdGhlIGZyZXF1ZW5jeSBvZiBjb3VudHJpZXMgd2l0aCB2YXJpb3VzIGxpZmUgZXhwZWN0YW5jaWVzIGNoYW5nZXMgb3ZlciB0aW1lLiAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQojZGYgJT4lIGdncGxvdChhZXMoeCA9IE5VTUVSSUNfVkFSSUFCTEUsIGNvbCA9IENBVEVHT1JJQ0FMX1ZBUklBQkxFKSkgKyBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMSkKCndvcmxkX2hlYWx0aF9lY29uICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBsaWZlX2V4cCwgY29sID0gYXMuZmFjdG9yKHllYXIpKSkgKyAKICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gNSkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKSArCiAgbGFicyh0aXRsZSA9ICJGcmVxdWVuY3kgb2YgTGlmZSBFeHBlY3RhbmNpZXMgYWNyb3NzIENvdW50cmllcyBieSBZZWFyIiwgeCA9ICJMaWZlIEV4cGVjdGFuY3kiLCB5ID0gIkNvdW50IG9mIENvdW50cmllcyIsIGNvbCA9ICJMaWZlIEV4cGVjdGFuY3kiKSArICMgVG8gYWRkIHRpdGxlcyBhbmQgbGFiZWxzCiAgdGhlbWVfYncoKSAKYGBgCgo+IE5vdGUgdGhhdCB0aGlzIGlzIG9uZSBwbG90IHRoYXQgaXMgcGFydGljdWxhcmx5IHN1c2NlcHRpYmxlIHRvIG1pc3NpbmcgZGF0YS4gSWYgY2VydGFpbiBjb3VudHJpZXMgZGlkIG5vdCByZXBvcnQgZGF0YSBpbiBjZXJ0YWluIHllYXJzLCB0aGUgY291bnQgb2YgY291bnRyaWVzIGluIGEgYnJhY2tldCB3aWxsIGFwcGVhciBsb3dlciwgbm90IG5lY2Vzc2FyaWx5IGJlY2F1c2UgZmV3ZXIgY291bnRyaWVzIGZlbGwgd2l0aGluIGEgY2VydGFpbiBsaWZlIGV4cGVjdGFuY3kgYnJhY2tldCwgYnV0IGJlY2F1c2UgZmV3ZXIgY291bnRyaWVzIHJlcG9ydGVkIHRoYXQgbGlmZSBleHBlY3RhbmN5LiAKCkFsdGVybmF0aXZlbHksIHlvdSBjb3VsZCB6b29tIGluIHRvIG9uZSB2YWx1ZSBpbiBvbmUgb2YgeW91ciBxdWFsaWZpZWQgdmFyaWFibGVzLCBmaWx0ZXJpbmcgdG8gYSBzcGVjaWZpYyBzdWJzZXQgb2Ygb2JzZXJ2YXRpb25zIGFuZCB0aGVuIGRpdmlkZSBieSBhIGRpZmZlcmVudCBjYXRlZ29yaWNhbCB2YXJpYWJsZS4gCgpgYGB7ciBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xMH0KI2RmICU+JSBnZ3Bsb3QoYWVzKHggPSBOVU1FUklDX1ZBUklBQkxFLCBjb2wgPSBDQVRFR09SSUNBTF9WQVJJQUJMRSkpICsgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDEpCgp3b3JsZF9oZWFsdGhfZWNvbiAlPiUgCiAgZmlsdGVyKHllYXIgPT0gbWF4KHllYXIsIG5hLnJtID0gVFJVRSkpICU+JQogIGdncGxvdChhZXMoeCA9IGxpZmVfZXhwLCBjb2wgPSBjb250aW5lbnQpKSArIAogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSA1KSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3Q9MSkpICsKICBsYWJzKHRpdGxlID0gIkZyZXF1ZW5jeSBvZiBMaWZlIEV4cGVjdGFuY2llcyBhY3Jvc3MgQ291bnRyaWVzIGJ5IENvbnRpbmVudCBpbiAyMDEwIiwgeCA9ICJMaWZlIEV4cGVjdGFuY3kiLCB5ID0gIkNvdW50IG9mIENvdW50cmllcyIsIGNvbCA9ICJDb250aW5lbnQiKSArICMgVG8gYWRkIHRpdGxlcyBhbmQgbGFiZWxzCiAgdGhlbWVfYncoKSAKYGBgCgojIyMgUG9pbnQgcGxvdHMKCipQb2ludCBwbG90cyogZGlzcGxheSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBhbmQgYSBudW1lcmljIHZhcmlhYmxlLgoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9MTB9CiNkZiAlPiUgZ2dwbG90KGFlcyh4ID0gQ0FURUdPUklDQUxfVkFSSUFCTEUsIHkgPSBOVU1FUklDX1ZBUklBQkxFKSkgKyBnZW9tX3BvaW50KCkKCmhvc3BpdGFscyAlPiUgCiAgZmlsdGVyKFNUQVRVUyA9PSAiT1BFTiIpICU+JQogIGdncGxvdChhZXMoeCA9IFRZUEUsIHkgPSBCRURTKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX2J3KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKSArCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgQmVkcyBpbiBIb3BzaXRhbHMgYnkgVHlwZSIsIHggPSAiVHlwZSIsIHkgPSAiTnVtYmVyIG9mIEJlZHMiKSArICMgVG8gYWRkIHRpdGxlcyBhbmQgbGFiZWxzCiAgdGhlbWVfYncoKSAKCiMgTm90ZSB0aGF0IHRoZSBwbG90IGFib3ZlIGV4aGliaXRzIG92ZXJwbG90dGluZyAtIHdoZW4gdGhlIGRhdGEgcmVwcmVzZW50ZWQgb24gYSBwbG90IG92ZXJsYXBzLCBtYWtpbmcgaXQgZGlmZmljdWx0IHRvIGRpc2Nlcm4gb25lIHBvaW50IGZyb20gdGhlIG5leHQuIFRoZXJlIGFyZSB2YXJpb3VzIHRvb2xzIGF2YWlsYWJsZSB0byBkZWFsIHdpdGggb3Zlci1wbG90dGluZy4gWW91IGNhbiByZWR1Y2UgdGhlIHNpemUgb2YgcG9pbnRzIG9uIHRoZSBwbG90LCBpbmNyZWFzZSB0aGVpciB0cmFuc3BhcmVuY3ksIG9yIHNldCB0aGVtIHRvIHNsaWdodGx5IG9mZnNldCBlYWNoIG90aGVyIChrbm93biBhcyBhZGRpbmcgaml0dGVyKS4gV2UgZG8gYWxsIHRocmVlIGJlbG93LgoKaG9zcGl0YWxzICU+JSAKICBmaWx0ZXIoU1RBVFVTID09ICJPUEVOIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0gVFlQRSwgeSA9IEJFRFMpKSArIAogIGdlb21faml0dGVyKHNpemUgPSAwLjUsIGFscGhhID0gMC4xKSArICNDaGFuZ2UgZ2VvbV9wb2ludCB0byBnZW9tX2ppdHRlciwgcmVkdWNlIHRoZSBzaXplLCBhZGQgdHJhbnNwYXJlbmN5IGZvciBvdmVycGxvdHRpbmcKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIEJlZHMgaW4gSG9wc2l0YWxzIGJ5IFR5cGUiLCB4ID0gIlR5cGUiLCB5ID0gIk51bWJlciBvZiBCZWRzIikgKyAjIFRvIGFkZCB0aXRsZXMgYW5kIGxhYmVscwogIHRoZW1lX2J3KCkgCgpgYGAKCiMjIyMgVGl0bGluZyBhIFBvaW50IFBsb3QKCk5vdGUgaG93IEkgdGl0bGVkIG15IHBsb3QgYWJvdmU6ICJOdW1iZXIgb2YgQmVkcyBpbiBIb3BzaXRhbHMgaW4gdGhlIFVTIHRoYXQgYXJlIE9wZW4gYnkgVHlwZSIgSGVyZSBJIGFtIGRpc3BsYXlpbmcgdGhlIG51bWJlciBvZiBiZWRzIGJ5IFR5cGUuIEEgZ29vZCBmb3JtdWxhIGZvciB0aXRsaW5nIHBvaW50IHBsb3RzIGlzIGFzIGZvbGxvd3M6CgpOdW1iZXIvTWVhc3VyZSBvZiBbeS1heGlzIHZhcmlhYmxlIG5hbWVdIGluIF9fX19fIGJ5IFt4LWF4aXMgdmFyaWFibGUgbmFtZV0gCgpUaGUgYmxhbmsgc2hvdWxkIGJlIGZpbGxlZCB3aXRoIHlvdXIgdW5pdCBvZiBvYnNlcnZhdGlvbi4gVGhlIFt4LWF4aXMgdmFyaWFibGUgbmFtZV0gc2hvdWxkIGJlIHlvdXIgeC1sYWJlbCBhbmQgIk51bWJlci9NZWFzdXJlIG9mIFt5LWF4aXMgdmFyaWFibGUgbmFtZV0iIHNob3VsZCBiZSB5b3VyIHktbGFiZWwuCgojIyMjIFdoYXQgaWYgSSBoYXZlIHF1YWxpZmllZCB1bml0cyBvZiBvYnNlcnZhdGlvbj8KCklmIHRoaXMgaXMgdGhlIGNhc2UgSSB3b3VsZCBlbmNvdXJhZ2UgeW91IHRvIGZpbHRlciB5b3VyIHBsb3QgdG8gb25lIHZhbHVlIGluIG9uZSBvZiB5b3VyIHF1YWxpZmllZCB2YXJpYWJsZXMuIEZvciBpbnN0YW5jZSBpZiB3b3JsZF9oZWFsdGhfZWNvbiBpcyBxdWFsaWZpZWQgYnkgY291bnRyeSBhbmQgeWVhciwgSSBjYW4gZmlsdGVyIHRvIHRoZSBtb3N0IHJlY2VudCB5ZWFyIGJlZm9yZSBjcmVhdGluZyBhIHBvaW50IHBsb3Qgb2YgdGhlIHByaXZhdGUgc2hhcmUgb2YgaGVhbHRoIHNwZW5kaW5nIGJ5IGNvbnRpbmVudC4KCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTEwfQp3b3JsZF9oZWFsdGhfZWNvbiAlPiUgCiAgZmlsdGVyKHllYXIgPT0gbWF4KHllYXIsIG5hLnJtID0gVFJVRSkpICU+JQogIGdncGxvdChhZXMoeCA9IGNvbnRpbmVudCwgeSA9IHByaXZfc2hhcmVfaGVhbHRoX3NwKSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAyLCBhbHBoYSA9IDAuOCkgKyAgCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3Q9MSkpICsKICBsYWJzKHRpdGxlID0gIk1lYXN1cmUgb2YgUHJpdmF0ZSBTaGFyZSBvZiBIZWFsdGggU3BlbmRpbmcgaW4gQ291bnRyaWVzIGJ5IENvbnRpbmVudCBpbiAyMDEwIiwgeCA9ICJDb250aW5lbnQiLCB5ID0gIk1lYXN1cmUgb2YgUHJpdmF0ZSBTaGFyZSBvZiBIZWFsdGggU3BlbmRpbmciKSArICMgVG8gYWRkIHRpdGxlcyBhbmQgbGFiZWxzCiAgdGhlbWVfYncoKSAKYGBgCgojIyMgU2NhdHRlcnBsb3RzCgoqU2NhdHRlcnBsb3RzKiBkaXNwbGF5IHRoZSByZWxhdGlvbnNoaXAgb3IgY29ycmVsYXRpb24gYmV0d2VlbiB0d28gbnVtZXJpYyB2YXJpYWJsZXMuCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KI2dncGxvdChkZiwgYWVzKHggPSBOVU1FUklDX1ZBUklBQkxFLCB5ID0gTlVNRVJJQ19WQVJJQUJMRSkpICsgZ2VvbV9wb2ludCgpCgpob3NwaXRhbHMgJT4lIAogIGZpbHRlcihTVEFUVVMgPT0gIk9QRU4iKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBCRURTLCB5ID0gUE9QVUxBVElPTikpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMC41KSArCiAgdGhlbWVfYncoKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgYmV0d2VlbiBIb3NwaXRhbCBCZWRzIGFuZCBQb3B1bGF0aW9uIGluIHRoZSBVUyIsIHggPSAiQmVkcyIsIHkgPSAiUG9wdWxhdGlvbiIpICsgIyBUbyBhZGQgdGl0bGVzIGFuZCBsYWJlbHMKICB0aGVtZV9idygpIApgYGAKPiBOb3RlIGhvdyB0aGlzIHBsb3QgaXMgcGFydGljdWxhcmx5IHVzZWZ1bCBmb3IgZmluZGluZyBvdXRsaWVycy4KCiMjIyMgVGl0bGluZyBhIFNjYXR0ZXJwbG90CgpOb3RlIGhvdyBJIHRpdGxlZCBteSBwbG90IGFib3ZlOiAiUmVsYXRpb25zaGlwIGJldHdlZW4gSG9zcGl0YWwgQmVkcyBhbmQgUG9wdWxhdGlvbiBpbiB0aGUgVVMiIEEgZ29vZCBmb3JtdWxhIGZvciB0aXRsaW5nIHNjYXR0ZXJwbG90cyBpcyBhcyBmb2xsb3dzOgoKUmVsYXRpb25zaGlwIGJldHdlZW4gX19fX18gW3gtYXhpcyB2YXJpYWJsZSBuYW1lXSBhbmQgW3ktYXhpcyB2YXJpYWJsZSBuYW1lXSAKClRoZSBibGFuayBzaG91bGQgYmUgZmlsbGVkIHdpdGggeW91ciB1bml0IG9mIG9ic2VydmF0aW9uLiBUaGUgW3gtYXhpcyB2YXJpYWJsZSBuYW1lXSBzaG91bGQgYmUgeW91ciB4LWxhYmVsIGFuZCBbeS1heGlzIHZhcmlhYmxlIG5hbWVdIiBzaG91bGQgYmUgeW91ciB5LWxhYmVsLgoKIyMjIyBXaGF0IGlmIEkgaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24/CgpJZiB0aGlzIGlzIHRoZSBjYXNlIEkgd291bGQgZW5jb3VyYWdlIHlvdSB0byBmaWx0ZXIgeW91ciBwbG90IHRvIG9uZSB2YWx1ZSBpbiBvbmUgb2YgeW91ciBxdWFsaWZpZWQgdmFyaWFibGVzLiBGb3IgaW5zdGFuY2UgaWYgd29ybGRfaGVhbHRoX2Vjb24gaXMgcXVhbGlmaWVkIGJ5IGNvdW50cnkgYW5kIHllYXIsIEkgY2FuIGZpbHRlciB0byB0aGUgbW9zdCByZWNlbnQgeWVhciBiZWZvcmUgY3JlYXRpbmcgYSBwb2ludCBwbG90IG9mIHRoZSBwcml2YXRlIHNoYXJlIG9mIGhlYWx0aCBzcGVuZGluZyBieSBjb250aW5lbnQuCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KI2dncGxvdChkZiwgYWVzKHggPSBOVU1FUklDX1ZBUklBQkxFLCB5ID0gTlVNRVJJQ19WQVJJQUJMRSkpICsgZ2VvbV9wb2ludCgpCgp3b3JsZF9oZWFsdGhfZWNvbiAlPiUgCiAgZmlsdGVyKHllYXIgPT0gbWF4KHllYXIsIG5hLnJtID0gVFJVRSkpICU+JQogIGdncGxvdChhZXMoeCA9IHRvdF9oZWFsdGhfc3BfcHAsIHkgPSBsaWZlX2V4cCwgc2l6ZSA9IHBvcCwgY29sID0gY29udGluZW50KSkgKyAKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHN0cm9rZSA9IDEpICsKICBsYWJzKHRpdGxlID0gIlJlbGF0aW9uc2hpcCBiZXR3ZWVuIENvdW50cnkgVG90YWwgSGVhbHRoIFNwZW5kaW5nIFBlciBQZXJzb24gYW5kIExpZmUgRXhwZWN0YW5jeSIsIHggPSAiVG90YWwgSGVhbHRoIFNwZW5kaW5nIFBlciBQZXJzb24iLCB5ID0gIkxpZmUgRXhwZWN0YW5jeSIsIHNpemUgPSAiUG9wdWxhdGlvbiIsIGNvbCA9ICJDb250aW5lbnQiKSArICMgVG8gYWRkIHRpdGxlcyBhbmQgbGFiZWxzCiAgdGhlbWVfYncoKSArCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygxLCAxMCksIGxhYmVscyA9IHNjYWxlczo6Y29tbWEpCmBgYAoKIyMjIFByb2R1Y2UgZm91ciBwbG90cyB0aGF0IHJlcHJlc2VudCBjby12YXJpYXRpb24gaW4geW91ciBkYXRhc2V0LiAKCllvdSBuZWVkIG5vdCBpbmNsdWRlIGV2ZXJ5IHBsb3QgSSBkZXNjcmliZWQgYWJvdmUuIEF0IHRoaXMgcG9pbnQsIHBsZWFzZSBjb250aW51ZSB0byBob2xkIG9mZiBvbiBzZWxlY3RpbmcgYSBnZW9ncmFwaGljIGNhdGVnb3JpY2FsIHZhcmlhYmxlLiBCZSBzdXJlIHRvIHpvb20gaW4gb3Igb3V0IG9uIHlvdXIgZGF0YSBpZiB5b3UgaGF2ZSBxdWFsaWZpZWQgdW5pdHMgb2Ygb2JzZXJ2YXRpb24uIAoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CiNGaWxsIHRoZSBjb2RlIGZvciBwbG90IDEgaGVyZS4gQWRkIGEgdGl0bGUgYW5kIGxhYmVscyB0byB5b3VyIHBsb3RzLiBCZSBzdXJlIHRvIGFkanVzdCBmb3Igb3ZlcnBsb3R0aW5nLgpgYGAKCldoYXQgcXVlc3Rpb24gbWlnaHQgdGhpcyBhbmFseXNpcyBoZWxwIHRvIGFkZHJlc3M/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKQXJlIHRoZXJlIGFueSBvdGhlciB2YXJpYWJsZXMgaW4geW91ciBkYXRhc2V0IHRoYXQgeW91IG5lZWQgdG8gdGFrZSBpbnRvIGNvbnNpZGVyYXRpb24gYmVmb3JlIGRpcmVjdGluZyB0aGlzIGFuYWx5c2lzIHRvd2FyZHMgYW5zd2VyaW5nIHRoYXQgcXVlc3Rpb24/IEluIG90aGVyIHdvcmRzLCBkbyB5b3UgbmVlZCB0byB6b29tIGludG8gYW55IHNwZWNpZmljIGFyZWFzIG9mIHRoZSBkYXRhc2V0IChieSBmaWx0ZXJpbmcpIGluIG9yZGVyIHRvIGFwcHJvcHJpYXRlbHkgYWRkcmVzcyB0aGlzIHF1ZXN0aW9uPyBJZiBzbywgd2hpY2g/IEJlIHN1cmUgdG8gYWRqdXN0IHlvdXIgcGxvdCBhYm92ZSB0byByZWZsZWN0IHRoaXMuCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKV2hhdCBpbnNpZ2h0IGNhbiB5b3UgZHJhdyBmcm9tIHRoaXMgcGxvdD8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0KI0ZpbGwgdGhlIGNvZGUgZm9yIHBsb3QgMiBoZXJlLiBBZGQgYSB0aXRsZSBhbmQgbGFiZWxzIHRvIHlvdXIgcGxvdHMuIEJlIHN1cmUgdG8gYWRqdXN0IGZvciBvdmVycGxvdHRpbmcuCmBgYAoKV2hhdCBxdWVzdGlvbiBtaWdodCB0aGlzIGFuYWx5c2lzIGhlbHAgdG8gYWRkcmVzcz8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpBcmUgdGhlcmUgYW55IG90aGVyIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGFzZXQgdGhhdCB5b3UgbmVlZCB0byB0YWtlIGludG8gY29uc2lkZXJhdGlvbiBiZWZvcmUgZGlyZWN0aW5nIHRoaXMgYW5hbHlzaXMgdG93YXJkcyBhbnN3ZXJpbmcgdGhhdCBxdWVzdGlvbj8gSW4gb3RoZXIgd29yZHMsIGRvIHlvdSBuZWVkIHRvIHpvb20gaW50byBhbnkgc3BlY2lmaWMgYXJlYXMgb2YgdGhlIGRhdGFzZXQgKGJ5IGZpbHRlcmluZykgaW4gb3JkZXIgdG8gYXBwcm9wcmlhdGVseSBhZGRyZXNzIHRoaXMgcXVlc3Rpb24/IElmIHNvLCB3aGljaD8gQmUgc3VyZSB0byBhZGp1c3QgeW91ciBwbG90IGFib3ZlIHRvIHJlZmxlY3QgdGhpcy4KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgpXaGF0IGluc2lnaHQgY2FuIHlvdSBkcmF3IGZyb20gdGhpcyBwbG90PwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTEwfQojRmlsbCB0aGUgY29kZSBmb3IgcGxvdCAzIGhlcmUuIEFkZCBhIHRpdGxlIGFuZCBsYWJlbHMgdG8geW91ciBwbG90cy4gQmUgc3VyZSB0byBhZGp1c3QgZm9yIG92ZXJwbG90dGluZy4KYGBgCgpXaGF0IHF1ZXN0aW9uIG1pZ2h0IHRoaXMgYW5hbHlzaXMgaGVscCB0byBhZGRyZXNzPwoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCkFyZSB0aGVyZSBhbnkgb3RoZXIgdmFyaWFibGVzIGluIHlvdXIgZGF0YXNldCB0aGF0IHlvdSBuZWVkIHRvIHRha2UgaW50byBjb25zaWRlcmF0aW9uIGJlZm9yZSBkaXJlY3RpbmcgdGhpcyBhbmFseXNpcyB0b3dhcmRzIGFuc3dlcmluZyB0aGF0IHF1ZXN0aW9uPyBJbiBvdGhlciB3b3JkcywgZG8geW91IG5lZWQgdG8gem9vbSBpbnRvIGFueSBzcGVjaWZpYyBhcmVhcyBvZiB0aGUgZGF0YXNldCAoYnkgZmlsdGVyaW5nKSBpbiBvcmRlciB0byBhcHByb3ByaWF0ZWx5IGFkZHJlc3MgdGhpcyBxdWVzdGlvbj8gSWYgc28sIHdoaWNoPyBCZSBzdXJlIHRvIGFkanVzdCB5b3VyIHBsb3QgYWJvdmUgdG8gcmVmbGVjdCB0aGlzLgoKYGBge3IgZXZhbD1GQUxTRX0KRmlsbCB5b3VyIHJlc3BvbnNlIGhlcmUuIApgYGAKCldoYXQgaW5zaWdodCBjYW4geW91IGRyYXcgZnJvbSB0aGlzIHBsb3Q/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9MTB9CiNGaWxsIHRoZSBjb2RlIGZvciBwbG90IDQgaGVyZS4gQWRkIGEgdGl0bGUgYW5kIGxhYmVscyB0byB5b3VyIHBsb3RzLiBCZSBzdXJlIHRvIGFkanVzdCBmb3Igb3ZlcnBsb3R0aW5nLgpgYGAKCldoYXQgcXVlc3Rpb24gbWlnaHQgdGhpcyBhbmFseXNpcyBoZWxwIHRvIGFkZHJlc3M/CgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKQXJlIHRoZXJlIGFueSBvdGhlciB2YXJpYWJsZXMgaW4geW91ciBkYXRhc2V0IHRoYXQgeW91IG5lZWQgdG8gdGFrZSBpbnRvIGNvbnNpZGVyYXRpb24gYmVmb3JlIGRpcmVjdGluZyB0aGlzIGFuYWx5c2lzIHRvd2FyZHMgYW5zd2VyaW5nIHRoYXQgcXVlc3Rpb24/IEluIG90aGVyIHdvcmRzLCBkbyB5b3UgbmVlZCB0byB6b29tIGludG8gYW55IHNwZWNpZmljIGFyZWFzIG9mIHRoZSBkYXRhc2V0IChieSBmaWx0ZXJpbmcpIGluIG9yZGVyIHRvIGFwcHJvcHJpYXRlbHkgYWRkcmVzcyB0aGlzIHF1ZXN0aW9uPyBJZiBzbywgd2hpY2g/IEJlIHN1cmUgdG8gYWRqdXN0IHlvdXIgcGxvdCBhYm92ZSB0byByZWZsZWN0IHRoaXMuCgpgYGB7ciBldmFsPUZBTFNFfQpGaWxsIHlvdXIgcmVzcG9uc2UgaGVyZS4gCmBgYAoKV2hhdCBpbnNpZ2h0IGNhbiB5b3UgZHJhdyBmcm9tIHRoaXMgcGxvdD8KCmBgYHtyIGV2YWw9RkFMU0V9CkZpbGwgeW91ciByZXNwb25zZSBoZXJlLiAKYGBgCgojIyBTdGFydCBhIHNoaW55IGFwcC4KCkF0IHRoaXMgcG9pbnQgaW4gdGhlIHF1YXJ0ZXIsIHdlIGFyZSBwcmVwYXJlZCB0byBzdGFydCBwaWVjaW5nIHRvZ2V0aGVyIGEgZGFzaGJvYXJkIGZvciBkaXNwbGF5aW5nIHRoZSBkYXRhLiBTaGlueSBBcHBzIGhhdmUgdHdvIGNvbXBvbmVudHMgLSBhIGZyb250IGVuZCAodWkpLCBhbmQgYSBiYWNrZW5kIChzZXJ2ZXIpLiBPbiB0aGUgZnJvbnQgZW5kLCB3ZSB3aWxsIGJlIGNvZGluZyBob3cgd2Ugd2FudCBvdXIgZGF0YSBkaXNwbGF5ZWQuICoqRm9yIHRoaXMgd2VlaywgdGhlIG9ubHkgdGhpbmcgeW91IG5lZWQgdG8gZG8gb24gdGhlIGZyb250IGVuZCBpcyBmaWxsIGluIHlvdXIgdGl0bGUuKiogT24gdGhlIGJhY2tlbmQsIHdlIHdpbGwgYmUgY29kaW5nIG91ciBkYXRhIGFuYWx5c2lzLiAKCkZpbGwgaW4geW91ciB0aXRsZSBpbiB0aGUgVUkuIAoKYGBge3J9CnVpIDwtIGRhc2hib2FyZFBhZ2UoCiAgCiAgZGFzaGJvYXJkSGVhZGVyKHRpdGxlID0gIlRJVExFIEhFUkUiKSwKICAKICBkYXNoYm9hcmRTaWRlYmFyKAogICAgI2lucHV0cyB3aWxsIGdvIGhlcmUuIAogICksCiAgCiAgZGFzaGJvYXJkQm9keSgKICAgICAgYm94KHBsb3RPdXRwdXQoInBsb3QxIikpLAogICAgICBib3gocGxvdE91dHB1dCgicGxvdDIiKSkKICApCikKYGBgCgpSZXBsYWNlIG15IHBsb3RzIGluIHRoZSBjb2RlIGJlbG93IHdpdGggdHdvIG9mIHRoZSBwbG90cyB0aGF0IHlvdSBjcmVhdGVkIGluIHRoaXMgbGFiLiAKYGBge3J9CnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0LCBzZXNzaW9uKSB7CiAgCiAgI1JFUExBQ0UgQkVMT1cgV0lUSCBZT1VSIE9XTiBQTE9UCiAgb3V0cHV0JHBsb3QxIDwtIHJlbmRlclBsb3QoewogICAgaG9zcGl0YWxzICU+JSBnZ3Bsb3QoYWVzKHggPSBUWVBFKSkgKyBnZW9tX2JhcigpCiAgI1JFUExBQ0UgQUJPVkUgV0lUSCBZT1VSIE9XTiBQTE9UCiAgICAKICB9KQogICNSRVBMQUNFIEJFTE9XIFdJVEggWU9VUiBPV04gUExPVAogIG91dHB1dCRwbG90MiA8LSByZW5kZXJQbG90KHsKICAgIGhvc3BpdGFscyAlPiUgZ2dwbG90KGFlcyh4ID0gVFlQRSkpICsgZ2VvbV9iYXIoKQogICNSRVBMQUNFIEFCT1ZFIFdJVEggWU9VUiBPV04gUExPVCAKICB9KQogIAp9CmBgYAoKYGBge3J9CnNoaW55QXBwKHVpLCBzZXJ2ZXIpCmBgYAoKV2hlbiB5b3Uga25pdCB0aGlzIG5vdGVib29rLCB5b3Ugd2lsbCBnZXQgYSBwcm9tcHQgYXNraW5nIHdoZXRoZXIgeW91IHdvdWxkIHByZWZlciB0byByZW5kZXIgYW5kIHJ1biB0aGlzIGRvY3VtZW50IGFzIFNoaW55LiBDbGljayBOby4gV2Ugd2lsbCBiZSBsZWF2aW5nIHRoaXMgbm90ZWJvb2sgaW4gYSBHaXRIdWIgZG9jdW1lbnQgZm9ybWF0LiAKCg==